之间有什么区别
#include <stdio.h>
int a[9];
int
main()
{
printf("%dn", a[1]);
}
和
#include <stdio.h>
int a[3][3];
int
main()
{
printf("%dn", a[1]);
}
我认为两者都导致在.bss
部分放置相同的36字节内存缓冲区,有什么区别?还是a[3][3]
的句法糖高于a[9] - a[3*3]
?
不,它们不相同,它们代表不同的类型。参考您的代码,
-
在第一种情况下,
a
是一维阵列。因此,a[1]
属于int
类型。§(要打印该值,
%d
即可。 -
然而,在第二种情况下,
a
是二维阵列。因此,a[1]
属于int [3]
类型。§(作为函数参数传递时,它会衰减为指向第一个元素的指针,基本上是
int *
。您将需要%p
来打印它(并根据%p
格式说明符的要求将指针强制转换为void *
(。
然而,如果你对这两个变量的内存布局感到困扰,你可以通过AnT或另一个详细说明多维数组内存布局的答案来检查另一个答案。
int a[3][3]
是int a[9]
上的语义糖。原始内存布局相同(即,它是9个int
的连续块(,但语言级别的访问语法不同。当访问a[3][3]
作为a[i][j]
时,编译器使用i * 3 + j
公式将表观2D索引转换为1D索引。后一种索引转换方案很容易扩展到任何数量的维度。
有什么区别
int a1[9];
和
int a2[3][3];
(我已经更改了名称,这样我就可以更容易地谈论声明了。(
不同之处在于它们属于不同的类型。它们都有相同的底层存储器布局,每个都由一个连续的存储器区域组成,该区域的大小是int
的9倍。但是a1
是9个int
对象的数组,而a2
是3个对象的数组——每个对象是3个int
对象的数组。它是一个多维数组,在C中,它恰好是数组的数组,没有更多,也没有更少。
区别不仅仅在于句法上的糖。对于某些操作,您可能会得到相同的生成代码,例如a1[1]
和a2[0][1]
。但是,例如,a1[3]
指的是数组a1
的第4个元素,而a2[0][3]
,尽管您可能认为它指的是同一个元素,但实际上具有未定义的行为。(允许但不要求编译器执行运行时数组绑定检查,并允许假设数组引用没有超过索引数组对象的末尾。(
printf("%dn", a2[1]);
正如其他人所提到的,这具有未定义的行为。CCD_ 31是类型为CCD_。在大多数上下文中,数组类型的表达式被转换为指针类型的表达式,因此a2[1]
的类型最终为int*
,并产生指向a2
第二行的初始元素的指针。要打印指针值,请使用%p
——这需要类型为void*
的参数,因此需要强制转换它:
printf("%pn", a2[1]);
推荐阅读:comp.lang.cFAQ第6节。