malloc的行为(0)

int main() { char *p; p = (char* ) malloc(sizeof(char) * 0); printf("Hello Enter the data without spaces :\n"); scanf("%s",p); printf("The entered string is %s\n",p); //puts(p); } 

在编译上面的代码并运行它时,程序能够读取字符串,即使我们为指针p分配了一个0字节的内存。

语句p = (char* ) malloc(0)实际发生了什么?

实现定义了malloc()将返回的内容,但使用该指针是未定义的行为。 并且未定义的行为意味着任何事情都可以从程序工作中完全发生而没有故障到崩溃,所有安全的赌注都是关闭的。

C99标准:

7.22.3内存管理function
第1段:

如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为就像大小是非零值一样,但返回的指针不应用于访问对象。

除了Als评论 – 会发生什么:你在某处写入内存并从那里检索数据。 因此,根据您的系统和操作系统类型,您会得到exception或只是一些未定义的行为

出于好奇,我在linux上使用gcc测试了你的代码,它比我预期的更强大(毕竟,将数据写入长度为0的字符缓冲区是未定义的行为……我希望它会崩溃) 。

这是我对你的代码的修改:

 #include  #include  int main() { char *p; p = malloc(sizeof(char)*0); printf("Hello Enter some without spaces :\n"); scanf("%s",p); char *q; q = malloc(sizeof(char)*0); printf("Hello Enter more data without spaces :\n"); scanf("%s",q); printf("The first string is '%s'\n",p); printf("The second string is '%s'\n",q); } 

我的第一个想法是,你可能会因为你只是将数据读入一个内存位置而被保存 – 如果你使用两个缓冲区,第二个可能会覆盖第一个…所以我把代码打破了输入和输出部分:

 Hello Enter some without spaces : asdf Hello Enter more data without spaces : tutututu The first string is 'asdf' The second string is 'tutututu' 

如果第一个缓冲区被覆盖,我们会看到

 The first string is 'tutututu' The second string is 'tutututu' 

事实并非如此。 [但这取决于你打包到每个缓冲区的数据量…见下文]

然后,我将大量数据粘贴到两个变量中:

 perl -e 'print "c" x 5000000 . "\n" ' | xsel -i 

(这将4个MB的’c’放入复制缓冲区)。 我将其粘贴到第一个和第二个scanf调用中。 该程序没有出现分段错误。

即使我没有分段错误,第一个缓冲区也会被覆盖。 我无法分辨,因为有太多的数据在屏幕上飞扬。 这是一个数据较少的运行:

 $ ./foo Hello Enter some without spaces : aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Hello Enter more data without spaces : ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc The first string is 'aaaaaaaaaaaa' The second string is '' 

aaaaaaaaaaa之后有一个小字形,这就是我的终端代表一个无法显示的unicode字符。 这是典型的覆盖数据:你不知道什么会覆盖你的数据…它是未定义的行为,所以你容易出现鼻子恶魔。

最重要的是,当你写入你没有分配空间的内存时(显式地使用malloc或隐式地使用数组),你正在玩火。 迟早,你会覆盖记忆并给自己带来各种各样的悲伤。

这里真正的教训是C不进行边界检查 。 它会很乐意让你写入你不拥有的记忆。 你可以整天做。 您的程序可能正常运行,但可能没有。 它可能会崩溃,它可能会写回损坏的数据,或者它可能会工作,直到您扫描的字节数比测试时使用的字节多一个。 它不关心,所以你必须。

malloc(0)情况只是这个问题的一个特例。