【问题标题】:Why does malloc work with zero size? [duplicate]为什么 malloc 以零大小工作? [复制]
【发布时间】:2015-10-26 13:10:21
【问题描述】:

这是我的代码

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

int main()
{

   char* p;
   p = (char*)malloc(0);
   scanf("%s", p);
   printf("%s", p);
   free(p);
}

有人可以向我解释为什么我通过终端输入的每个单词都会打印给用户吗?我有malloc(0)。当我尝试scanf 给我segmentation fault 时不应该吗?

编辑

为什么这会给我一个编译错误:

p = malloc(sizeof(char) * 2)

当我试图避免(void*)

error: cannot initialize a variable of type 'char *' with an rvalue of type 'void *'

【问题讨论】:

  • 您正在处理未定义的行为。
  • @Korpel:它不起作用。你只是幸运。 en.wikipedia.org/wiki/Undefined_behavior
  • 还有,像往常一样please don't cast the result of malloc()
  • 为什么你认为将任意长度的字符串扫描到大小为 1 字节的缓冲区中将比大小为 0 字节的缓冲区定义得更多?
  • 如果最后一行(没有强制转换)触发编译错误,可能是因为您使用的是 C++ 编译器而不是 C 编译器。在 C 语言中,有一个明确定义的与 void* 之间的隐式转换。

标签: c pointers memory malloc


【解决方案1】:

malloc 的 C 标准明确规定了这一点:

如果请求的空间大小为 0,则行为为 实现定义:返回的值应为空 指针或唯一指针。

对于来自malloc的返回值:

如果 size 为 0,则可以是空指针或唯一指针 成功传递给 free() 应返回。否则,应 返回一个空指针并设置 errno 来指示错误。

关于调用scanf的分段错误,纯粹是基于环境的实现和运行时行为,只是运气而不是任何事情,下次运行时,它可能因分段错误而崩溃。

【讨论】:

  • 您实际上是在引用 POSIX 标准,而不是 C 标准。虽然 POSIX 标准包含大量来自 C 标准的复制/粘贴。
  • @Lundin - C 标准中的语言大致相同,只是在不同的部分(7.22.3)下:“如果请求的空间大小为零,则行为是实现-定义:要么返回一个空指针,要么行为就像大小是某个非零值,但返回的指针不应用于访问对象。"
  • 注意:C 标准没有指定设置errno。建议在引用部分添加引用。
【解决方案2】:

C 标准 9899:2011 7.22.3 规定:

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

意思是malloc返回的是实现定义的行为。您必须阅读您的特定编译器文档才能了解它在您的情况下的作用:返回一个空指针或指向 0 字节数据的非零指针(可能是随机垃圾位置)。

在任何一种情况下,返回的指针都没有指向有效的内存位置。因此,如果您尝试写入它,您将调用未定义的行为。这意味着任何事情都可能发生:程序可能崩溃并烧毁,或者它看起来正常工作并在一个月后崩溃,或者其他任何事情。

为什么这会给我一个编译错误:p = malloc(sizeof(char) * 2)

因为您尝试使用 C++ 编译器编译 C 代码。不要那样做。一些 C++ 编译器有一个选项,您可以设置为使用 C 编译器进行编译。


关于 C 标准不一致的旁注:

标准附录 J 实际上将上述行为列为未指定行为。我怀疑这一定是附件 J 中的错误,因为上面引用的规范性文本明确指出这是实现定义的。 7.22.3 是规范性的,附件 J 是信息性的,所以我将忽略附件 J。

【讨论】:

  • @Quentin 你是对的......已修复。
  • 现在这是一个很好的答案,谢谢:)
【解决方案3】:

来自opengroup -

如果请求的空间大小为 0,则行为由实现定义:返回的值应为空指针或唯一指针。

malloc(0) 没有分配任何内容。因此,当您尝试使用scanf 获取输入时,您会调用未定义的行为

当我尝试 scanf 时不应该给我一个分段错误?

不,当你有 UB 时就没有必要了。也许你没有那么幸运得到分段错误并获得所需的输出(这可能会混淆)。

【讨论】:

  • 实现定义的行为不是未定义的行为。
  • @Lundin 我没这么说。我说过,当 OP 尝试使用 scanf 获取输入时,它会调用 UB。如果它可能听起来模棱两可,对不起。
  • @Lundin 我说清楚了。这可能造成了误解:-)
  • 现在确实更清晰了:)
猜你喜欢
  • 2010-11-07
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 2012-04-12
  • 2012-07-29
  • 2014-04-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多