解除引用malloc(0)

时间:2018-01-01 18:31:31

标签: c malloc

C11标准中malloc(0)的行为引用了以下*:

  

void * malloc(size_t size);

           

如果size为零,则行为是实现定义的(可能返回空指针,或者可能返回一些可能不用于访问存储的非空指针,但必须通过免费)。

           

*(引自cppreference.com而不是官方的ISO / IEC 9899:2011标准,为the former needs to be purchased。)

根据这个定义,我不希望以下工作(使用icc 18.0.0编译):

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

int main(int argc, char **argv)
{
    double *u = malloc(0);
    u[0] = 3.0;
    printf("The value of u[0] is %lf", u[0]);
    free(u);
    return 0;
}

令人惊讶的是它起作用并给出了输出:

The value of u[0] is 3.000000
Process finished with exit code 0

似乎u[0] = 3.0;访问存储空间。如果malloc返回NULL,则会导致细分错误。

我是否误解了访问存储的概念,或者是否还有其他事情发生?

更新/澄清

我的问题的关键似乎在于“ 可能不能用于访问存储”的措辞,以及“可能不会”意味着不应该不能。我已经读过这个意思,无论返回什么指针都不能被取消引用(除非realloc'd)。

我发现I can use more memory than how much I've allocated with malloc(), why?的答案非常适用于这个问题。主要的一点是,在分配的内存之外写入是未定义的行为,虽然这无疑是错误的,但它并不是保证抛出和错误。

问题what's the point in malloc(0)?有几个答案提到返回的指针。

4 个答案:

答案 0 :(得分:6)

你打电话给malloc并要求指向一些你可以存储一些数据的内存的指针。您承诺在那里存储的数据不超过0个字节。然后你作弊,或违反了规则,并在那里存储了sizeof(double)个字节数。

也许你预料到,既然你违反了规则,那么坏事和明显的事就会出错。但事实证明,写一个malloc指针而不是你所允许的更多是未定义行为的例子,这意味着什么 - 绝对任何东西 - 可能发生。而且,至关重要的是,可能发生的事情之一是,您的程序似乎可以工作,即使它不是&#34;假设&#34;到。

有点像这样:假设你在半夜沿着一条空无一人的街道行驶,你就会发出红光。由于没有交叉路口,周围没有其他人,当然也没有警察,你决定欺骗并开车穿过十字路口而不等待灯变绿。但是这是什么?没有车撞到你身上。你不会贬低任何行人。没有警察给你一张票。怎么会这样?运行红灯错误,对吧?

嗯,当然,这并不奇怪。你已经观察到没有交叉路口,没有行人,也没有警察。但是,如果这些事情中的任何一个突然出现在最后一刻并且已经是一次意外或不舒服的警察采访,那你就会出错了。

情况与您的代码相同。你得到了#34;幸运&#34;,并没有明显出错 - 但代码错误

未定义的行为很棘手,很难想到。但是要理解它的一件大事是,你通常可以期望获得错误消息。实际上,未定义行为的定义方面之一是编译器需要提供有关它的任何错误消息。

如果您有点好奇,请在this answer查看有关未定义行为的详情。

答案 1 :(得分:5)

您正在处理未定义的行为。你应该清楚这一点。

无论什么它都不会分配任何内存,你可以放任何东西(就像你在这里做的那样)。

谨防NULL支票在这里工作 - 因为当您通过NULL时, 会返回0malloc

甚至建议每当你将一些值传递给malloc时,检查它是否为非零正整数。如果它0没有打电话给malloc - 它没有任何用处。

答案 2 :(得分:3)

声明

double *u = malloc(0);

使语句的行为依赖于语句

的实现
u[0] = 3.0;

当然会调用未定义的行为,因为标准清楚地表明返回指针不应用于访问对象。因此,您不能通过malloc(0)取消引用指针返回。

§7.22.3(p1):

  

[...],但返回的指针不得用于访问对象。

答案 3 :(得分:1)

正如其他答案向您解释,行为是undefined。你应该scared

顺便说一句,您可以在printf("u is %p\n", (void*)u);之后添加一些malloc

但是,在我的Linux / Debian系统上,malloc主要由C standard library实现,glibc通常是GNU musl-libc(但可能是其他内容,如free software ),malloc/malloc.c。你可以查看glibc的src/malloc/malloc.c文件并理解malloc(0)给出了一些有效的指针。对于musl-libc,请参阅其malloc function attribute文件。

FWIW,编译器知道malloc,主要是GCC optimizesImage 1