我怎么能初始化分配了零字节的指针呢?

时间:2019-01-28 02:30:21

标签: c pointers memory malloc

我知道malloc(size_t size)分配大小字节并返回指向分配的内存的指针。

那么当我为整数指针p分配零字节时,我仍然能够对其进行初始化吗?

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

int main()
{

        int *p = malloc(0);
        *p = 10;

        printf("Pointer address is: %p\n", p);
        printf("The value of the pointer: %d\n", *p);

        return 0;
}

这是我的程序输出,我正在期待分段错误。

Pointer address is: 0x1ebd260
The value of the pointer: 10

5 个答案:

答案 0 :(得分:3)

malloc(0)的行为是由实现定义的,它将返回一个指针或NULL。根据C标准,当请求零大小空间 1)时,不应使用malloc返回的指针。

取消引用malloc(0)返回的指针是未定义的行为,其中包括程序可能执行不正确(崩溃或无提示地生成不正确的结果),或者可能偶然地完成了程序员想要的操作。


1)来自C标准#7.22.3p1 [已添加强调]

  

1未指定连续调用对aligned_alloc,calloc,malloc和realloc函数分配的存储的顺序和连续性。如果分配成功,则返回的指针将进行适当对齐,以便可以将其分配给具有基本对齐要求的任何类型的对象的指针,然后将其用于在分配的空间中访问此类对象或此类对象的数组(直到空间已明确释放)。分配对象的生命周期从分配一直到释放为止。每个这样的分配都应产生一个指向与任何其他对象不相交的对象的指针。返回的指针指向分配空间的开始(最低字节地址)。如果无法分配空间,则返回空指针。 如果请求的空间大小为零,则行为是实现定义的:返回空指针,或者行为类似于该大小为某个非零值,不同之处在于返回的指针不用于访问对象。

答案 1 :(得分:1)

调用malloc(0)并写入返回的缓冲区时,将调用undefined behavior。这意味着您无法预测程序的行为。它可能会崩溃,可能会输出奇怪的结果,或者(在这种情况下)它似乎可以正常工作。

仅仅因为程序可能崩溃并不意味着它

答案 2 :(得分:0)

通常,C不会阻止您做错事。

int *p = malloc(0);之后,p具有一些价值。它可能是一个空指针,或者可能指向一个或多个字节的内存。在任何一种情况下,您都不应使用它。 1 但是C语言不会阻止您这样做。

执行*p = 10;时,编译器可能已生成代码,将10写入p指向的位置。 p可能指向实际的可写内存,因此可以执行存储指令而不会失败。然后,您已将10写入不应该在内存中的位置。在这一点上,C标准不再指定程序的行为—通过写在不合适的地方,您已经破坏了C工作方式的模型。

在这种情况下,编译器也有可能认识到*p = 10;是不正确的代码,并且生成了上述写入存储器以外的内容。一个好的编译器可能会为您提供有关此代码的警告消息,但是C标准没有强制编译器这样做,并且它可以使您的程序以其他方式中断。

脚注

1 如果malloc返回空指针,则不应写入*p,因为它没有指向对象。如果它返回其他内容,则不应写入*p,因为C 2018 7.22.3.1对此malloc(0)说,“返回的指针不得用于访问对象。”

答案 3 :(得分:0)

我认为查看细分错误定义https://en.wikipedia.org/wiki/Segmentation_fault

是个好主意

以下是分段错误的一些典型原因:

  • 尝试访问不存在的内存地址(进程的地址空间外)
  • 尝试访问程序无权访问内存(例如,进程上下文中的内核结构)
  • 尝试写入只读内存(例如代码段)

因此,通常,访问程序数据段中的任何地址都不会导致seg错误。这种方法具有意义,因为C中没有任何带有内存管理的框架(例如C#或Java)。因此,在此示例中,由于malloc返回某个地址(非NULL),因此它从程序的数据段返回该地址,程序可以访问该数据段。

但是,如果程序很复杂,则此类操作(*p = 10)可能会覆盖属于其他变量或对象(甚至是指针!)的数据,并导致不确定的行为(包括段错误)。

但是请注意,如其他答案所述,该程序不是最佳实践,您不应在生产中使用这种方法。

答案 4 :(得分:-1)

CribsController.js

当分配的大小为0时,它已经为您提供了指向内存第一个地址的指针