关于C语言多维数组声明与指针访问结果的疑问
关于C语言多维数组声明与指针访问结果的疑问
嗨,我来帮你理清这里的两个关键点——多维数组的初始化规则,以及指针访问背后的内存布局问题。
首先说初始化的部分:你以为必须用{{1,2,3},{4,5,6}}这种双层大括号的形式初始化二维数组,但其实C语言允许省略内层的大括号。当你写int arr[2][3] = {1,2,3,4,5};时,编译器会按照行优先的顺序,把列表里的元素依次填充到数组的每个位置:先填满第一行的3个元素(1、2、3),再填第二行的前两个(4、5),剩下的元素(第二行第三个)会被自动初始化为0。所以这个声明完全合法,不会报错,它等价于int arr[2][3] = {{1,2,3}, {4,5,0}};。
接下来解释为什么(*arr)[4]会得到5:
- 首先,二维数组名
arr在表达式中(除了sizeof和取地址&的场景)会隐式转换为指向数组第一行的指针,也就是int (*)[3]类型的指针(指向一个包含3个int的数组)。 *arr就是对这个指针解引用,得到的是第一行的数组本身(arr[0],类型是int[3])。而当这个一维数组名出现在表达式中时,又会再次转换为指向其第一个元素的指针(int*类型,指向arr[0][0])。- 所以
(*arr)[4]本质上是*( (int*)arr + 4 )——也就是从数组的起始地址开始,偏移4个int的位置去访问内存。而二维数组在内存里是连续存储的,整个arr的内存布局是:1, 2, 3, 4, 5, 0(连续排列),偏移4个位置正好是第5个元素(下标从0开始),也就是5。
不过要特别提醒:这种写法其实属于数组越界访问,因为(*arr)代表的是第一行的3元素数组,[4]已经超出了它的合法下标范围(应该是0-2)。虽然当前编译器下你得到了预期的结果,但这是标准里定义的「未定义行为」——换个编译器、编译选项甚至运行环境,结果可能完全不同,甚至导致程序崩溃。所以实际开发中绝对不要依赖这种写法。
内容来源于stack exchange
相关产品推荐
相关产品推荐

