代码:
#include <stdio.h>
int main(void)
{
int arr[2][3] = {{1,2,3},{4,5,6}};
int i, j;
for(i = 0; i < 2; i++)
{
for(j = 0; j < 3; j++)
{
printf("%d ", *((*arr+(i*3))+j));
}
printf("n");
}
return 0;
}
我很惊讶上面的代码如何给出输出:
1 2 3
4 5 6
我知道*(arr+i) == arr[i]
,也知道我应该使用arr[i][j]
而不是让一切变得更复杂,但我不明白*((*arr+(i*3))+j)
是如何工作的。
在我的理解中,*((*arr+(i*3))+j)
可以简化为*((*arr)+(i*3)+j)
,因为*
(间接寻址运算符(在这里具有最优先的优先级。
因此,当 i
为零并且 j
遍历 0 到 2 时,表达式与打印第一个子数组整数的 arr[0][j]
相同。
当i
变成 1 时,我的困惑就会增加。接下来的三个表达式将是*((*arr)+(1*3)+0)
、*((*arr)+(1*3)+1)
和*((*arr)+(1*3)+2)
,可以简化为arr[0][3]
、arr[0][4]
和arr[0][5]
。
这如何打印最后三个值?
int arr[2][3] = {{1,2,3},{4,5,6}};
在内存中:
1 | 2 | 3 | 4 | 5 | 6
each number on an adjacent memory "cell" the size of an int, in this order
第二行 : i = 1 j = 0
*((*arr+(i*3))+j)) means *((*arr + 3) + 0)-> *({1, 2, 3} + 3) -> *({4, 5, 6}) = 4
请记住,x[n]
等同于*(x + n)
,无论x
或n
。(这也意味着arr[1]
相当于*(arr + 1)
,*(1 + arr)
等等1[arr]
我觉得很有趣(
这里arr[1][0]
:x
是arr[1]
的,n
是0
所以第一等价:*(arr[1] + 0)
第二x
是arr
,n
是1
如此*(*(arr + 1) + 0)
。
最后arr + 1
的意思是arr + sizeof(*arr)
的地址,意思是: (arr + 1)
等效于 (*arr + 3)
,因为*arr
是arr[0]
类型int[3]
C 语言以所谓的行主顺序存储多维数组,因此,当您声明int arr[2][3]
内存实际上是布局的,数组的条目彼此相邻此序列中的内存:
arr[0][0] arr[0][1] arr[0][2] arr[1][0] arr[1][1] arr[1][2]
这有几个有用的后果:
-
arr[1]
就像指向一维数组的指针一样。 就像当您声明int **arr;
. - 初始化列表中的初始值设定项将按照您列出它们的顺序复制到内存位置。
数组存储在您的内存中,如下所示:
_____ _____ _____ _____ _____ _____
| 1 | | 2 | | 3 | | 4 | | 5 | | 6 |
----- ----- ----- ----- ----- -----
因此,即使它存储在二维数组中,它也会在编译期间传染性地分配内存。当你写 a[1][1] 时,编译器从前面访问 (1*(列数( + 1 ( 位置,即从开始的 4 位置。
见 http://www.fredosaurus.com/notes-cpp/arrayptr/23two-dim-array-memory-layout.html