【问题标题】:Malloc'd char array has unexpected outputMalloc 的 char 数组有意外的输出
【发布时间】:2017-10-29 03:58:42
【问题描述】:

我的问题很简单,我不明白为什么这个程序不能正确输出:

int size = 35;
// malloc size for text
char *txt = malloc(size * sizeof(char *));
if(!txt) {
    fprintf(stderr, "Allocation for text data failed.\n");
    return EXIT_FAILURE;
}

for(int i = 0; i < size; i++) { // for each character in text
    txt[i] = 'a';
}
printf("%s\n", txt);
free(txt);

预期输出:

呸呸呸呸呸呸呸呸

实际输出:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa8 9 10 1 0 12 11 6 37 44 3 45 56 0 64 77 5 68 83 0 39 46 0 19 16 9 8 2 6 3 1 4 17 12 9 17 6 0 25 10 3 31 16 13 21 9 9 11 7 4 2 3 0 7 6 1 9 5 2 11 2 5 19 6 13 21 8 15 8 0 0 7 0 0 29 20 13 62 50 0 49 35 0 41 27 1 38 25 9 25 13 0 21 11 0 24


尝试使用valgrind --leak-check=yes 进行调试,它显示的唯一错误如下:

==3999== 条件跳转或移动取决于未初始化的值
==3999== 在 0x4C30F78:strlen(在 /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中)
==3999== 由 0x4EA969B: 放置 (ioputs.c:35)
==3999== by 0x400B39: main (decode.c:85) // 这是 printf 行

我以为是因为它不知道什么时候停止打印,但我尝试了:

while(txt != NULL) {
    printf("%c", *(txt++));
}

我也试过了:

txt[size - 1] = '\0';

while((*txt) != '\0') {
    printf("%c", *(txt++));
}

那些结果更糟,它会用特殊字符填充我的控制台。

【问题讨论】:

  • 您似乎忘记了 C 中的 char 字符串实际上称为 null-terminated 字节字符串。 null-termination 部分很重要。完成后,您可以将其打印为字符串。另请注意,这意味着 35 个字符的字符串需要 36 个字符的空间以适应终止符。
  • malloc(size * sizeof(char *)); 你想要 35 个字符,而不是 35 个字符指针。
  • 哦,顺便说一句,malloc(size * sizeof(char *))size 分配了足够的内存指针char

标签: c printf malloc valgrind


【解决方案1】:

\0 放入char 数组中。否则printf 将有undefined behavior

同样在malloc 中,您分配给char 而不是char*

示例

int size = 35;
// malloc size for text
char *txt = malloc((size+1) * sizeof(char ));
if(!txt) {
    fprintf(stderr, "Allocation for text data failed.\n");
    return EXIT_FAILURE;
}
memset(txt,0,size+1); 
for(int i = 0; i < size; i++) { // for each character in text
    txt[i] = 'a';
}

printf("%s\n", txt);
free(txt);
txt=NULL;
  1. 也可以设置txt[size]='\0',因为所有其他位置都被输入的字符覆盖。 [彼得对此发表了评论]

【讨论】:

  • 感谢您的回答!正如我在帖子末尾指定的那样,我还尝试在 char 数组中添加 '\0' 并没有得到太多运气。我尝试使用不带 * 的 sizeof(char) 并得到分段错误。你能提供一个可行的例子吗?
  • @PaulLemarchand:您可以查看示例
  • 哇,我现在看到了我的错误,再次非常感谢。只用 %c 尝试了 while(*(txt) != '\0'),而不是简单地用 %s。 memset 在那里必不可少吗?
  • @PaulLemarchand.: 只需将 char 数组清零即可。您也可以采用其他方式
  • 可以在循环之后执行txt[size] = '\0',而不是循环之前的memset(text, 0, sizeof(text))。无论如何,循环都会将txt[0] 覆盖到txt[size-1],所以不需要memset 那些。
【解决方案2】:
int size = 35;
// malloc size for text
char *txt = malloc(size * sizeof(char *));

您没有分配 35 个字节,而是 35 个指针(即 32 位上的 140 个字节或 64 位上的 280 个字节)。

这应该是 'malloc(size * sizeof(char))' 或只是 malloc(size)。

for(int i = 0; i < size; i++) { // for each character in text
    txt[i] = 'a';
}

您只初始化了分配的 140 或 280 个字节中的前 35 个。 你没有空终止你的字符串。

printf("%s\n", txt);

现在您正在打印一个非空终止的字符串和 valgrind 已正确警告您它正在​​访问未初始化的内存 尝试对输入的 txt 执行 strlen()。

【讨论】:

    【解决方案3】:

    char *txt = malloc(size + 1); ...

    for(int i = 0; i < size; i++) { // for each character in text
        txt[i] = 'a';
    }
    txt[size] = '\0';
    printf("%s\n", txt);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-11
      • 1970-01-01
      相关资源
      最近更新 更多