【发布时间】:2016-07-19 19:47:30
【问题描述】:
以下代码是否正确?
假设已知所有对象指针类型具有相同的大小和对齐方式,大小不大于 8。
// allocate some space to A, and set *A and **A to different regions of that space
char*** A = malloc(92);
*A = (char**)( (char*)A + 2*sizeof(char**) );
**A = (char*)*A + 4*sizeof(char*);
// initialize the second char** object
A[1] = *A + 2;
// write four strings further out in the space
strcpy(A[0][0],"string-0-0");
A[0][1] = A[0][0] + strlen(A[0][0]) + 1;
strcpy(A[0][1],"string-0-1");
A[1][0] = A[0][1] + strlen(A[0][1]) + 1;
strcpy(A[1][0],"string-1-0");
A[1][1] = A[1][0] + strlen(A[1][0]) + 1;
strcpy(A[1][1],"string-1-1");
我发现这样的东西在如何释放对象可能并不直接的情况下很有用。例如,假设 A[1][1] 可能会或可能不会重新分配给字符串文字的地址。无论哪种方式,您都只需释放 A。此外,对 malloc 的调用次数也将降至最低。
我担心这可能不是正确的代码是基于以下内容。使用标准的草案版本,我有:
7.22.3 内存管理函数
- ...如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向具有基本对齐要求的任何类型对象的指针,然后用于访问此类对象或此类对象的数组分配的空间(直到空间被显式释放)...
所以我保证能够将空间用作单一类型的数组。我找不到任何可以将其用作两种不同类型(char* 和 char**)的数组的保证。请注意,将某些空间用作 char 数组是唯一的,因为任何对象都可以作为字符类型数组访问。
有效类型的规则与此方法一致,因为没有单独的字节被用作两种不同类型的一部分。
虽然上面表明似乎没有明确违反标准,但标准也没有明确允许这种行为,我们有第 4 章的第 2 段(强调添加):
如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。未定义的行为在本国际标准中以“未定义的行为”一词或省略任何明确的行为定义来表示。这三者在重点上没有区别;它们都描述了“未定义的行为”。
当内存模型本身如此模糊时,这有点模糊。使用 malloc() 返回的空间来存储任何(一个)类型的数组显然需要明确的允许,我在上面引用了这个允许。因此有人可能会争辩说,将该空间用于不同类型的不相交数组也需要明确允许,如果没有它,则按照第 4 章的规定作为未定义行为。
所以,具体来说,如果代码示例是正确的,那么根据上面引用的标准的第 4 章的部分,它没有明确定义因此未定义的论点有什么问题?
【问题讨论】:
-
char*** A = malloc(90);错误,指针大小为 8 -
@4386427,谢谢,我的算术有点草率。
-
@4386427,我得到 6 个大小为 8 的指针,大小为 6*8=48,长度为 10 的 4 个字符串分别为 44、48+44=92。
-
你知道C有
structs吗? -
malloc(92)让我眼前一亮。永远不要那样做。真的。用于初始化非char指针的malloc应始终将sizeof表达式作为参数。
标签: c arrays pointers memory-management c11