分配指向结构的指针,但不是实际的结构

Allocate pointer to struct, but not actual struct

我使用 malloc 分配了指向 struct 的指针的内存,但我没有为实际结构分配任何内容。但是我可以 access/use struct.

typedef struct A
{
  int w;
  int x;
  int y;
  int z;
}A;

int main(void) 
{
  A* a = malloc(sizeof(A*));  //Here I allocate memory just to pointer to A

  //Why can I do this than?:
  a->z = 10;
  a->w = 456;
  return 0;
}

为什么这样做? 这只是巧合还是它总是应该以这种方式工作? 一些注意事项:

  1. 我无法通过非动态分配做到这一点

  2. 测试于repl.it

malloc 调用分配请求的字节数和 returns 一个指针 到分配的内存块的开头。

A* a = malloc(sizeof(A*));

您在这里请求 sizeof(A*) 字节,但是您请求的字节数 请求是指向 A 的指针。但是,您需要一个字节的数量 A 对象,可能不一样。这似乎是一个微小的差异,但它 是一个巨大的。你应该做的是:

A *a = malloc(sizeof(A));

甚至更好

A *a = malloc(sizeof *a);

第二个更好,因为你不能犯错误,它总是会传递给 malloc 正确的字节数。当使用 sizeof(<type>) 时很容易制作 错误并在不需要时添加 *,就像您对 sizeof(A*).

所做的那样

I couldn't do that with non-dynamic allocation

好吧,你可以。对于一个简单的结构,您可以在不从中请求内存的情况下对其进行初始化 堆(通过 malloc):

A a;
a.z = 10;
a.w = 456;

A a = { .z = 10, .w = 456 };

也会这样做。

我们通常选择对结构体使用malloc的原因是结构体 可能非常大,可能需要很多字节的内存。您拥有的 space 数量 与变量函数相比,变量函数的堆栈框架非常小 您在堆部分中拥有的内存。所以最好从 堆使用 malloc。它还允许您将该指针传递给其他人 函数,即使在请求内存的函数结束之后。

不过你忘记了两件事:

  • 经常查看malloc的return,可能是NULL.
  • 最后释放内存。当你不需要内存时:

    free(a);
    

没有人说你应该做什么。这样做:

int main(void) 
{
  A* a = malloc(sizeof(A));  // Here I allocate an ins6tance of A and set a pointer to it

  a->z = 10;
  a->w = 456;
  return 0;
}

当你这样做时:

A* a = malloc(sizeof(A*));

您没有为 A 的实例分配足够的内存。因此,如果您读取/写入的任何成员恰好超出了实际分配的范围,您将调用 undefined behavior.

对于未定义的行为,您无法准确预测程序的输出。它可能会崩溃,可能会输出奇怪的结果,或者(在您的情况下)它可能看起来工作正常。如何通过进行看似无关的修改(例如额外的局部变量、调用 printf 进行调试或通过使用不同的选项重新编译)来改变未定义的行为清单。

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

如果您使用 valgrind 等工具,它可以在您不正确地使用内存时捕获,例如在您的示例中。

实际上这将取决于实际的 CPU 体系结构和操作系统来判断这是否有效:

第一个问题是:什么是sizeof(A),什么是sizeof(A *)

我不知道 CPU 不等式 sizeof(A) <= sizeof(A *) 是否成立,但 CPUs(或具有外部存储器电路的计算机)至少是可能的.

在这种情况下,您的代码可以正常工作,因为 malloc 分配了足够的内存来保存结构 A

如果不给出此条件,则取决于malloc的实际执行情况。许多实现会舍入 malloc 的参数,因此 malloc(5) 实际上会分配 16 个字节,而不是 5 个字节。

如果 malloc 将分配多达或超过 sizeof(A) 字节,一切都很好。

如果malloc分配少于sizeof(A)字节,则取决于分配的内存之后的内存是否使用以及是否存在的问题:

如果分配内存后的内存不存在(例如,在使用 MMU 时未映射),您将收到错误消息,具体取决于系统 - 在大多数现代计算机上,会有一个 "exception" 和您的程序会崩溃。

如果该内存之后的内存被其他数据占用,您将覆盖该数据,这可能会导致错误。

如果该内存之后的内存存在但未使用,您的程序将正常运行。