我从堆中分配内存来存储一个字符,但它持有一个字符串

时间:2017-09-30 08:00:12

标签: c string character heap-memory allocation

#include<stdio.h>
#include<stdlib.h>
int main()
{
    char* name;
    name=(char* )malloc(sizeof(char)); 
    printf("Enter a name: ");
    scanf("%s",name);
    printf("%s",name);
    return 0;
}

当我为单个字符分配内存时,上面的代码完美地存储了整个字符串。这怎么可能?

3 个答案:

答案 0 :(得分:2)

你有undefined behavior。非常scared。阅读Lattner's blog on UB

printf("%s",name);

name是一个真正的字符串(这是一个以零字节结尾的合法且有效的内存区域)时,这是有效的。在您的程序中它不是,您正在访问malloc - ed区域之后的至少一个字节。你有一个buffer overflow

当单个字符区域是有效字符串时,唯一的情况是单个char包含零字节,因此该字符串为空。

  

上面的代码完美地存储了整个字符串

你运气不好(BTW,它不是“完美”)。它可能更糟(例如宇宙崩溃)并且可能更好(例如一些segmentation violationnasal demons,......)。这就是你应该害怕UB的原因。

(为了解释您的特定计算机上发生的情况,您需要深入了解实现细节,例如研究您的操作系统,编译器,指令集,编译器生成的汇编代码等等...... ;你不想在这方面花费多年的工作,即使你这样做也留在UB)

您应该编译所有警告和调试信息(gcc -Wall -Wextra -g)并使用调试器gdbvalgrind并确保您的程序正在处理的每个内存位置都有效。< / p>

BTW malloc可能会失败,您应该对此进行测试,sizeof(char)按定义1.您应该尝试

char* name = malloc(80);
if (!name) { perror("malloc"); exit(EXIT_FAILURE); };

请同时阅读您正在使用的所有功能的文档。从printfmalloc以及scanf开始。请注意,您使用scanf是危险的。最好使用printf结束\n控制字符串或适当使用fflush(因为stdout通常是行缓冲的)。还下载并研究n1570编程语言的规范C11

在某些系统上,您拥有的不仅仅是C11标准所保证的。例如,POSIX有getline,您可以像here一样使用它。如果你没有POSIX系统,也要考虑fgets(在C11标准中)(那么你需要复杂的技巧来读取任意长行,或者指定和文档你的程序如果使用malloc(80)),则只能处理最多79个字节的行。

代码中avoid arbitrary limits的礼貌很好;当然你的计算机仍然有局限性(你可能无法处理一千亿字节的行)。

请注意character encoding(另请参阅this)。立即使用2017年的UTF-8 everywhere {例如helplibunistring {},但请记住,glib字符可以跨越几个字节(即char - s)。

答案 1 :(得分:1)

您只为一个字符分配了内存,这足以存储终止空字节。你需要分配更多。

例如:

char *name = malloc(128); /* allocates 128 bytes */
printf("Enter a name: ");
if (fgets(name, 128, stdin) == NULL) {
    /* input failure */
}

请注意scanf() is notorious for reading input。更喜欢fgets()。另请注意,如果您有空间可能要删除,fgets()会在换行符中读取。

另见:Why does some code carefully cast the values returned by malloc to the pointer type being allocated?

答案 2 :(得分:1)

您只能将一个字符串安全地存储到该数组中,并且该字符串的长度为零。

也许,对于你的财富,这段代码似乎可以在你的余生中发挥作用,而且你永远不会听到任何关于它的抱怨......但是 不可能的。

输入更多字符;用几KB将键盘压缩,我打赌你会开始看到分段错误。很高兴我告诉你这个,因为我可能为你节省了很多时间的调试!

话虽如此,我无法提供100%的保证;这只是一个有根据的猜测。也许您的系统没有段错误。也许你的系统让黑客绕过了安全性。谁知道?行为未定义

由于编码不安全,我本可以为您节省诉讼,但除了标准编程语言给出的定义之外,我们无法对未定义行为进行定义,是:非便携式不稳定

现在应该清楚避免这种情况的原因。