8
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)

4

3 回答 3

12

它是实现定义的malloc()将返回的内容,但使用该指针是未定义的行为。未定义的行为意味着任何事情都可能发生,从程序正常运行到崩溃,所有安全的赌注都被取消了。

C99 标准:

7.22.3 内存管理功能
第 1 段:

如果请求的空间大小为零,则行为是实现定义的:要么返回空指针,要么行为好像大小是某个非零值,但返回的指针不应用于访问对象.

于 2012-05-21T11:43:46.040 回答
0

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

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

#include <stdio.h>
#include <stdlib.h>

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 'ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc'

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

底线是,当您写入尚未分配空间的内存时(显式使用 malloc 或隐式使用数组),您就是在玩火。迟早,你会覆盖记忆,给自己带来各种各样的悲伤。

这里真正的教训是C 不做边界检查。它会很高兴地让你写入你不拥有的内存。你可以整天这样做。您的程序可能会正确运行,也可能不会。它可能会崩溃,它可能会写回损坏的数据,或者它可能会工作,直到您扫描的字节比测试时使用的多一个字节。它不在乎,所以你必须这样做。

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

于 2012-05-21T13:35:59.237 回答
0

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

于 2012-05-21T12:29:14.380 回答