在C语言中,二维数组元素的地址认知是一个相对复杂但重要的概念。以下是对二维数组中元素地址认知的详细叙述:
一、二维数组的基本构成
二维数组可以被看作是由多个一维数组组成的数组。例如,定义了一个3行4列的二维数组,
int a[3][4] = { {1,3,5,7},
{9,11,13,15},
{17,19,21,23}
}
其中a[0]
, a[1]
, a[2]
分别代表这个二维数组中的三个一维数组(即行),同时也是这三个一维数组的首地址,本身代表的是一个地址,而不是二维数组中一个元素的值,并不能代表对应行的首元素值作为输出。即
printf("%d",a[0]);
是错误的,因为它本身是一个地址,不能作为一个值输出。
printf("%d",*a[0]);
是正确的且输出结果为1,即第一行一维数组首元素的值。
二、二维数组名的含义
- 二维数组名是一个地址常量:二维数组名(如
a
)是一个指向其首元素的指针,即指向第一个一维数组(或第一行)的指针。在C语言中,数组名代表数组首元素的地址,因此a
的值是二维数组首元素(即第一行)的地址。 - 二维数组名与行指针:二维数组名也可以被理解为行指针,它指向的是一个一维数组(行)的首地址。
- 二维数组名 = 第一个一维数组(或第一行)的地址 = 存放的是二维数组第一个元素的值
三、二维数组中元素的地址
- 首元素的地址:二维数组的首元素地址是
&a[0][0]
,它同时也是二维数组名a
的值。 - 行地址:
a+i
(其中i
是非负整数)表示二维数组中第i
行的首地址。例如,a+1
是第二行(即a[1]
)的首地址。a[i]
(其中i
是非负整数且小于行数)也是第i
行的首地址,同时它也是一个一维数组名,代表一个一维数组(即一行)。
- 列地址:
- 在二维数组中,我们通常不直接谈论“列地址”的概念,因为列是通过行和列索引来定位的。但是,我们可以说
a[i]+j
(其中i
是行索引,j
是列索引)表示第i
行第j
个元素的地址。例如,a[0]+1
是第一行第二个元素的地址(即&a[0][1]
)。
- 在二维数组中,我们通常不直接谈论“列地址”的概念,因为列是通过行和列索引来定位的。但是,我们可以说
- 元素的值与地址:
- 要获取二维数组中某个元素的值,我们可以使用
a[i][j]
的形式。 - 要获取该元素的地址,我们可以使用
&a[i][j]
。
- 要获取二维数组中某个元素的值,我们可以使用
四、二维数组地址的等价表示
在C语言中,二维数组的地址可以通过多种方式等价表示:
(1)a[i]
等价于 *(a+i)
等价于a+i,都表示第i
行的首地址。
为什么 *(a+i)
可以作为地址使用
当 a
是一个二维数组时,a
本身是数组名代表首元素地址,等价于一个指向其第一行的指针。因此,a+i
计算出的是指向第 i
行的指针(注意这里的“行”本身也是一个数组或一维数组)。在二维数组中,*(a+i)
或等价地 a[i]他们是一个指向一个一维数组的指针,本身的值就是指向的数组的首元素的地址
。
*(a+i)
在这个上下文中通常被视为一个数组名(或行指针),而不是一个具体的值。要访问第 i
行第 j
列的元素,我们需要进一步解引用,即 *(*(a+i)+j)
或 a[i][j]
。
总结来说,*(a+i)
可以作为地址使用,因为它通过解引用操作获取了指针所指向的值,而这个值实际上是数组元素的地址。
(2)a[i]+j
等价于 *(a+i)+j,
都表示第i
行第j
个元素的地址,但是
不
等价于(a+i)+j
。
a[i]+j
:a[i]
表示二维数组 a
的第 i
行的首地址。由于数组是连续存储的,a[i]
实际上指向了第 i
行的第一个元素的内存地址。a[i]+j
表示从第 i
行的首地址开始,向后偏移 j
个整数的位置。这正好是第 i
行第 j
列元素的地址。
*(a+i)+j
:首先通过 (a+i)
获取指向第 i
行的一个指针,通过解引用运算符 * 获得这个指针的值即第 i 行首元素的地址,然后 +j
等同于在内存地址上向后偏移 j
个整数的位置,因此也得到了第 i
行第 j
列元素的地址。
(a+i)+j:a
是指向二维数组首元素的指针。a+i
表示从 a
开始,按照数组的行数来偏移。如果数组的每行有 N
个元素,那么 a+i
实际上偏移了 i*N
个整数的位置,指向第i行的第一个元素。(a+i)+j
这里再次使用 +j
,并不是在内存地址上简单偏移两个整数,而是根据数组的行数来偏移。这意味着 (a+i)+j
实际上相当于 (a + i*N) + j*N
,即从第二行的首地址开始,再偏移 j*N
个整数的位置。
五、注意事项
- 在处理二维数组时,要注意不要越界访问数组元素,这可能会导致未定义行为。
- 数组名是一个常量指针,不能对其进行赋值操作(如
a++
是非法的),但可以通过指针算术来访问数组的不同部分。