了解 malloc 和灵活的数组成员

Understanding malloc and flexible array members

我很好奇 malloc() 实际上是如何分配内存的。我正在阅读 K.N.King 的 C 编程以供参考。特别是第 17 章。最初在 void *malloc(size_t size) 章中被描述为分配 size 字节内存块和 return 指向该内存块的 void * 指针的函数。两个主要的应用程序正在动态分配字符串和数组。当调用 malloc() 时,returned 指针将被转换为适当的类型,例如

int *n;
n = malloc(sizeof(*n));

malloc() return 将转换为 (int *)。据我了解,由于发生了这种转换,因此调用 malloc() 分配的内存块包含未初始化的整数。然而,在阅读了本章的更多内容后,我认为我错了,但我无法弄清楚到底发生了什么。

在阅读灵活数组成员一章的最后一节时发生了理解冲突。定义最后一个成员为“不完整”的结构的想法,即

struct vstring {
    int len;
    char chars[];
};

作者接着说,我引用:

A structure that contains a flexible array member is an incomplete type. An incomplete type is missing part of the information needed to determine how much memory it requires. ... In particular, an incomplete type can't be a member of another structure or an element of an array. However, and array may contains pointers to structure that have a flexible array member.

很明显,我之前的理解一定是有缺陷的,否则这样的调用,

struct vstring *str = malloc(sizeof(struct vstring) + n);

会分配一个包含不完整类型的数组。

malloc()分配的内存块在强制转换后是否是特定类型的数组?如果不是,那下面的怎么行,

struct node {
    int value;
    struct node *next;
};

struct node *new_node = malloc(sizeof(*new_node));
new_node->value = 10;

如果 malloc() 调用分配的内存未声明为 struct node 的元素?即使是我放在 post 开头的整数数组示例,我也可以通过立即下标 n 来访问分配内存的元素。

the malloc() return will be cast to (int *).

n = malloc(sizeof(*n)); 中没有演员表。强制转换是源代码中的显式运算符,就像加号是加法运算符或星号是乘法运算符一样。强制转换是括号中的类型名称。在n = malloc(sizeof(*n));中,malloc返回的值自动转换为n的类型,即int *。这是转换,不是转换。

Is the block of memory allocated by malloc() an array of a particular type after being cast?

malloc分配的内存没有声明类型。由于 C 标准中的形式语义和技术原因,一旦将数据存储到其中,它就会采用有效类型。这在很大程度上与普通使用无关,只要您不尝试对内存做任何“有趣”的事情,例如将它用作不同类型的不同类型。

If not, then how can the following work…

一旦您使用 malloc 为对象分配了足够的内存,您就可以将该对象的值存储到分配的内存中。

… if the memory allocated by the malloc() call is not declared as elements of struct node?

内存的有效类型由用于存储到内存的lvalue表达式的类型决定。 lvalue 是一个可能指定对象的表达式。对于已声明的对象,与 int x; 一样,对象的名称 x 是它的左值表达式。当我们有一个指针时,如 int *p;,那么 *pp 指向的对象的左值表达式(假设它是指向此类对象的内存的有效指针,而不是空指针或无效指针)。

已分配 new_node 指向用 malloc 分配的内存,然后 *new_node 是适当类型的左值表达式, struct node,并且 new_node->valuestruct nodeint 成员的左值表达式。使用这些左值表达式通知编译器如何处理这些位置的内存。