指针数组初始化为复合字面量数组。

3
我目前正在阅读《理解和使用C指针》这本书,我在其中遇到了以下例子:
int (*(arr1[])) = {(int[]){0,1,2}, (int[]) {3,4,5}, (int[]){6,7,8}}

作者随后展示了arr1[0][0]...arr1[2][2]的内存布局,可以看到元素被存储在连续的区域中。
对于这个例子,我有两个问题:
1. 我不明白为什么在声明arr1时需要第一个方括号,也就是说,与以下声明有何区别:
int *(arr1[]) = ...

我读到的是:arr1被声明为一个包含指向整数的指针的数组。
2. 我真的不明白为什么这个例子会导致一个连续的块。因为: 如果我初始化一个数组,我会写成:
a = {...}

并用逗号分隔列出元素。现在,在上面的例子中,arr1的元素应该是指针(除非我对声明的理解有误)。因此,我认为第一个成员应该是
int *(arr1[])= {(int[]){0,1,2},...

创建一个包含0、1、2的数组,并返回其地址(这对应于int[]的转换),然后将其作为第一个指针的值使用。然而,如果这是真的,那么数字0、1、2将位于与数字3、4、5可能不同的内存段中。
有人能进一步解释一下吗?

你说得对,最内层的括号可以省略。这只是个人风格、品味等等的问题。 - alagner
请告知这本书的名称,以便我们将其添加至即将发布的黑名单中。 - Lundin
是这个吗?https://www.amazon.com/Understanding-Using-Pointers-Techniques-Management/dp/1449344186 - Lundin
@dbush 目前还没有。这本书的推荐已经乱套了,我们花了很多次迭代才将其破坏到现在的状态。当这该死的东西被恢复后,我呼吁提高质量标准并引入黑名单此处,但这个提议并没有得到太多关注。 - Lundin
回复:“那么数字0、1、2可能会被存储在一个独立的内存中”:有时事物并不如其潜力所预期。 “潜力”意味着某些事情可能发生,并不意味着它一定会发生。 - Eric Postpischil
显示剩余2条评论
3个回答

5
在声明中,int (*(arr1[])) 中的括号都是可选的。使用 int *arr1[] 是等效且更易读的写法。
至于连续地址的复合字面量,没有要求它们一定是连续的。虽然在同一作用域中声明的复合字面量(和命名变量)具有相似的地址范围是有意义的,但编译器可以自由地安排它们的位置。
当我尝试创建给定的数组并打印每个元素的地址时,我得到了以下结果:
0x7ffdf47f3880
0x7ffdf47f3890
0x7ffdf47f38a0

在这种特殊情况下,复合字面量的地址是递增的,但它们并不相邻。每个字面量之间有4个字节的间隔,因此它们不是连续的。

谢谢你澄清了一下,但是关于地址的问题:我指的是arr1[0][0]....arr1[2][2]的地址,而不是这三个指针的地址。 - P.Jo
@P.Jo 数组元素的地址,即arr1[0][0] ... arr1[0][2]将始终是连续的,但不是单个复合字面量。如上所述,复合字面量之间相隔16个字节,但每个字面量的大小为12个字节,因此它们之间有4个字节的间隙。 - dbush
我明白对于一个真正的多维数组,但是对于上面的声明arr[0]是第一个int*指针,它可能指向与arr[1]完全不同的位置 - 这是错误的吗? - P.Jo
@P.Jo 是的,arr[0]arr[1] 指向两个不同的复合字面量。在上面的例子中,它们碰巧靠近彼此,但并不紧邻。 - dbush

2
我不明白为什么在声明arr1时需要第一个括号。
实际上,它并不需要。写这段代码的人可能是困惑了,可能不应该写编程书籍,以免将他们的困惑传给其他人。
更常见的写法是int* arr1[],不需要括号。声明使用与"运算符优先级"相同的规则,意味着int* arr1[]始终等价于int* (arr1[])。从那里添加更多的括号并没有任何作用:int (((*(arr1[]))))仍然是相同的类型...
我理解为:arr1被声明为包含指向整数的指针的数组。
正确。
我真的不明白为什么示例结果是连续的块。
C语言并不保证这一点,所以我能理解你的困惑。像其他数组一样,复合字面量也不能保证具有连续的分配。它们可能相邻,也可能不相邻,这取决于编译器和系统。

只有真正的多维数组才能保证是连续的,但在这里你只有一个指针数组,每个指针指向一个单独的数组,在编译器看来是分散分配的。

然而,每个复合字面量中的3个int项当然是相邻的。

总体上,你似乎对C语言比你不幸碰到的那本书的作者更了解。所以我建议停止阅读这本书,公开批评它,在互联网上发表负面评论等等。(我们仍然需要一个反书推荐黑名单。)


谢谢你把这个解释清楚了!嗯,我并不是专家。我觉得这本书大部分还好,但在那个特定的章节里有一些令人困惑的地方。但如果你从头开始学习,这些小问题可能会花费很多时间。就像数学书中的一个公式错误一样。 - P.Jo

0

对于指向C声明的阅读,有一个运算符优先级规则,在我看来真的非常有帮助。

能往右走就往右走,必须往左走时再往左走

为了更好地理解,您可以查看下面的链接。该来源是在SO的另一个问题答案中建议的(我不太记得了):

http://unixwiz.net/techtips/reading-cdecl.html


你的回答可以通过提供更多的支持性信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的回答是否正确。你可以在帮助中心找到更多关于如何撰写好回答的信息。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接