如何使用指针访问二维数组?
先来看看在一维数组中怎样使用指针访问数组:
一维数组中 a[i] 中的 a 代表了本数组的首地址,相当于 &a[0]。
因此 *a 就等于 a[0]。
那么对 a 加 1,就可以访问下一位:
*(a+1) 就等于 a[1]。
可以看出,指针与数组的关系非常密切。好像两个类型没有什么差别,只是换个形式来表达而已。
其实这是因为数组在内存中是一块连续的空间。这时候使用指针形式和数组形式来访问数组并没有差别。
那么在二维数组中如何用指针访问呢?
我们首先来看看二维数组的构成以及如何访问:
与一维数组类似的是,a[i][j] 中的 a 也代表了该数组在内存中的首地址。a 相当于 &a[0][0]。
可以将二维数组看作是由两个一维数组构成的。假设有 a[2][2] 这样一个二维数组,可以这么理解它:a 由 a[0],a[1],a[2] 构成,而 a[0] 又由 a[0][0],a[0][1],a[0][2] 构成,a[1] 由 a[1][0],a[1][1],a[1][2] 构成,a[2] 由 a[2][0],a[2][1],a[2][2] 构成。
所以如果将二维数组这样(将序号用 a[i] 表示)来描述,会更加清晰:
[0] | [1] | [2] | |
---|---|---|---|
a[0] | 5 | 2 | 1 |
a[1] | 1 | 3 | 1 |
a[2] | 4 | 1 | 4 |
我们可以清晰地看到每一个 a[i][j] 都代表了谁:
- a[0],a[1],a[2] 分别代表了那一整行,比如 a[1] 代表了 "1 3 1" 这个一维数组。
- 加上列标,可以访问那一行中的某一个元素,比如 a[0][0] 就是 5。
知道二维数组的概念并会使用二维数组的方式来访问数组后,我们就可以来谈谈如何用指针访问二维数组了。
a 由 a[0],a[1],a[2] 构成,而 a[0] 又由 a[0][1],a[0][1],a[0][2] 构成
两个一维数组构成了一个二维数组。a 是一个二维数组,a[i] 是一个一维数组。既然 a[i] 是一个数组,那么数组名就是这个数组的首地址。比如,a[0] 就等同于 &a[0][0]。
地址一旦出现,指针就可以登场了。
a 是一个数组名,它有三个元素:a[0],a[1],a[2]。所以:
*a 等于 a[0], *(a+1) 等于 a[1], *(a+2) 等于 a[2]。
a[0], a[1], a[2] 又都是各个一维数组的首地址。比如 a[0] 就等同于 &a[0][0],就是说 *a[0] = a[0][0]。
再结合上面的 *a 等于 a[0],可以得出:**a 等于 a[0][0]。
以 a[2][2] 为例,指针与数组的等价关系如下表所示:
数组元素 | 指针访问 |
---|---|
a[0][0] | **a |
a[0][1] | *(*a+1) |
a[0][2] | *(*a+2) |
a[1][0] | **(a+1) |
a[1][1] | *(*(a+1)+1) |
a[1][2] | *(*(a+1)+2) |
a[2][0] | **(a+2) |
a[2][1] | *(*(a+2)+1) |
a[2][2] | *(*(a+2)+2) |
虽然看起来很繁琐,但是可以总结成一句话:
二维数组 a[i][j] 中的 a[i] 是一个一维数组名,也就是一个地址量。
再记住二维数组的描述图:
[0] | [1] | [2] | |
---|---|---|---|
a[0] | |||
a[1] | |||
a[2] |
记住这两个点,就可以清晰地明确二维数组的概念以及如何用指针访问二维数组中的元素了。
字符串二维数组
我们知道字符串是一个一维数组,那么多个字符串就可以用字符串数组来表达。
现在我们来定义并初始化一个二维数组:
char s[3][5] = {"I", "love", "you"};
上面定义了一个 3 行 5 列的二维数组。在内存中存放格式如下:
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
s[0] | I |