gpt4 book ai didi

c - 仅基于 printf 语句的程序段错误

转载 作者:太空宇宙 更新时间:2023-11-04 01:19:22 24 4
gpt4 key购买 nike

在进行 K&R 练习时,我遇到了一种我无法理解的行为,而且我在 SOF 上找不到任何解决方案:

程序(将基数为 10 的整数转换为基数 n 字符串)在我额外的 printf() 语句下运行良好。一旦我开始删除或注释掉它们,意想不到的行为就开始了

完整代码:

#include <stdio.h>
#include <string.h>
#include <assert.h>

#define MAXLINE 1000

char numtochar(unsigned n);
void reverse(char s[]);
void itob(int n, char s[], unsigned b);

int main() {
// test numtochar
assert(numtochar(1) == '1');
assert(numtochar(11) == 'b');
assert(numtochar(61) == 'Z');
assert(numtochar(62) == '+');
// test reverse
char t[] = "TestiNg";
reverse(t);
assert(!strcmp(t, "gNitseT"));
// test itob
printf("if this is commented out, it will segfault\n");
char s[MAXLINE];
itob(10, s, 10);
printf("%s\n", s);
assert(strcmp(s, "10") == 0);
itob(11, s, 2);
printf("%s\n", s);
assert(strcmp(s, "1011") == 0);
itob(100, s, 8);
printf("%s\n", s);
assert(strcmp(s, "144") == 0);
itob(1337, s, 32);
printf("%s\n", s);
assert(strcmp(s, "19p") == 0);
itob(127, s, 64);
printf("%s\n", s);
assert(strcmp(s, "1/") == 0);
return 0;
}

/* This numbering is not standard base-64, but will be consistent so long
* as base <= 64
* 0..63 => 0..9a..zA..Z+/
*/
char numtochar(unsigned n) {
assert(n < 64);
if (n < 10)
return ('0' + n);
else if (n >= 10 && n < 36)
return ('a' + (n - 10));
else if (n >= 36 && n < 62)
return ('A' + (n - 36));
else if (n == 62)
return '+';
else if (n == 63)
return '/';
}

void reverse(char s[]) {
int c, i, j;
for (i=0, j=strlen(s)-1; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
return;
}

void itob(int n, char s[], unsigned b) {
assert(b <= 64);
int c, i, sign;
if ((sign = n) < 0)
n = -n;
do {
s[i++] = numtochar(n % b);
} while ((n /= b) != 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
return;
}

如下所示,如果我运行所有 printf 语句,它会按预期运行。如果我注释掉第一条语句,它会运行一次但不会再次运行。

user@laptop:~/git/ansi_c/ch3 $ make ex05.o # no printf statements commented
gcc -o ex05.o ex05.c
user@laptop:~/git/ansi_c/ch3 $ ./ex05.o
if this is commented out, it will segfault
10
1011
144
19p
1/
user@laptop:~/git/ansi_c/ch3 $ make ex05.o # comment out first printf statement
gcc -o ex05.o ex05.c
user@laptop:~/git/ansi_c/ch3 $ ./ex05.o
10
1011
144
19p
1/
user@laptop:~/git/ansi_c/ch3 $ make ex05.o # resave after no changes
gcc -o ex05.o ex05.c
user@laptop:~/git/ansi_c/ch3 $ ./ex05.o
Segmentation fault (core dumped)

但是,如果我取消注释掉第一个 printf 语句并注释掉第二个语句 (printf("%s\n", s);),itob 的结果不再通过断言声明。

user@laptop:~/git/ansi_c/ch3 $ make ex05.o # uncomment first printf, comment second
gcc -o ex05.o ex05.c
user@laptop:~/git/ansi_c/ch3 $ ./ex05.o
if this is commented out, it will segfault
101101
ex05.o: ex05.c:33: main: Assertion `strcmp(s, "1011") == 0' failed.
Aborted (core dumped)

gcc 版本是 7.2.1

如果我删除所有 printf 语句,它也会出现段错误。作为 C 的新手,我不确定如果这确实是问题所在,我可能在哪里分配内存不足,因为我看到的所有类似问题都围绕着 malloc 的使用展开。

最佳答案

在 C 中要学习的一件重要事情是,如果您不使用值初始化变量然后访问它,它将导致未定义的行为。以这个函数为例...

void itob(int n, char s[], unsigned b) {
assert(b <= 64);
int c, i, sign;
if ((sign = n) < 0)
n = -n;
do {
s[i++] = numtochar(n % b);
} while ((n /= b) != 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
return;
}

i 一开始有什么值?它可能是 0,但它实际上是当时内存中恰好存在的随机值。这就是为什么取消注释代码会改变事情,因为它会影响 i 的值。

只需将其更改为以值 0 开头即可解决您的问题。还删除了 c,因为它未被使用

int i = 0, sign;

valgrind 是一个很好用的工具 - 它会告诉您内存损坏和泄漏发生的位置。

关于c - 仅基于 printf 语句的程序段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48059841/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com