前言:
目标:需要了解及掌握数组指针的行地址、列地址、具体元素地址、具体元素地址的值是怎样定义及实现。
重点:指针的偏移,指针解引用。
难点:指针的升阶与降阶。
1. 基本概念
-
二维数组:二维数组可以看作是一个数组的数组。例如,
int a[3][4]
表示一个 3 行 4 列的二维数组。 -
数组指针:数组指针是一个指针,指向一个数组。例如,
int (*p)[4]
表示一个指向包含 4 个整数的数组的指针。 -
指针数组:指针数组是一个数组,其元素是指针。例如,
int *p[3]
表示一个包含 3 个整型指针的数组。 -
数组名与指针的区别:
-
数组名:在大多数情况下,数组名可以被视为指向其第一个元素的指针。
-
指针:指针是一个变量,可以指向任何类型的变量,并且可以被重新赋值。
-
-
指针运算:
-
指针加减:指针加减操作会根据指针类型调整偏移量。例如,
int *p; p + 1
表示p
向前移动一个int
的大小。 -
指针解引用:使用
*
运算符访问指针指向的值。
-
-
二维数组的指针表示:
-
int arr[3][4];
中,arr
是一个指向int [4]
的指针。 -
arr[0]
是一个指向int
的指针,表示第一行的第一个元素。 -
arr[i]
等价于*(arr + i)
,表示第i
行的第一个元素。
-
-
行地址和列地址的区别:二维数组中每一行的行地址和每一行第一列地址在数值上是相同的,但含义不同。行地址是指向整个行的指针,而列地址是指向行中某个元素的指针。
-
二维数组的地址:二维数组的名字
a
本身就是一个指向第一行的指针,即a
等价于&a[0]
。
2.二维数组的内存布局
对于二维数组 int arr[2][3];的内存布局如下:
对于二维数组 int arr[3][4];
,内存布局如下:
arr[0][0] arr[0][1] arr[0][2] arr[0][3]
arr[1][0] arr[1][1] arr[1][2] arr[1][3]
arr[2][0] arr[2][1] arr[2][2] arr[2][3]
假设每个 int
占用4字节,内存地址如下:
arr[0][0] -> 0x7ffee3b8e990
arr[0][1] -> 0x7ffee3b8e994
arr[0][2] -> 0x7ffee3b8e998
arr[0][3] -> 0x7ffee3b8e99c
arr[1][0] -> 0x7ffee3b8e9a0
arr[1][1] -> 0x7ffee3b8e9a4
arr[1][2] -> 0x7ffee3b8e9a8
arr[1][3] -> 0x7ffee3b8e9ac
arr[2][0] -> 0x7ffee3b8e9b0
arr[2][1] -> 0x7ffee3b8e9b4
arr[2][2] -> 0x7ffee3b8e9b8
arr[2][3] -> 0x7ffee3b8e9bc
3. 二维数组指针代码分析
#include <stdio.h>
int main() {
int arr[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 行地址
printf("第一行地址: %p\n", (void *)arr);
printf("第二行地址: %p\n", (void *)(arr + 1));
printf("第三行地址: %p\n", (void *)(arr + 2));
// 列地址
printf("第一行第一列地址: %p\n", (void *)arr[0]);
printf("第一行第二列地址: %p\n", (void *)(arr[0] + 1));
printf("第二行第一列地址: %p\n", (void *)(*(arr + 1)));
// 具体元素地址
printf("a[1][2]的地址: %p\n", (void *)(arr[1] + 2));
printf("a[1][2]的地址: %p\n", (void *)(*(arr + 1) + 2));
printf("a[1][2]的地址: %p\n", (void *)&arr[1][2]);
// 具体元素的值
printf("a[1][2]的值: %d\n", *(arr[1] + 2));
printf("a[1][2]的值: %d\n", *(*(arr + 1) + 2));
printf("a[1][2]的值: %d\n", arr[1][2]);
return 0;
}
4. 地址运算
- & 运算符:地址升阶,将一个元素的地址提升为指向该元素所在行的指针。
- *运算符:地址降阶,将一个行地址降阶为该行中某个元素的地址。
5.二维数组指针行地址表示
-
arr
:-
arr
是一个指向int [4]
的指针,表示第一行的地址。 -
输出:
0x7ffee3b8e990
-
-
arr + 1
:-
arr + 1
是一个指向int [4]
的指针,表示第二行的地址。 -
输出:
0x7ffee3b8e9a0
-
-
arr + 2
:-
arr + 2
是一个指向int [4]
的指针,表示第三行的地址。 -
输出:
0x7ffee3b8e9b0
-
6.二维数组指针列地址表示
-
arr[0]
:-
arr[0]
是一个指向int
的指针,表示第一行第一个元素的地址。 -
输出:
0x7ffee3b8e990
-
-
arr[0] + 1
:-
arr[0] + 1
是一个指向int
的指针,表示第一行第二个元素的地址。 -
输出:
0x7ffee3b8e994
-
-
*(arr + 1)
:-
*(arr + 1)
等价于arr[1]
,是一个指向int
的指针,表示第二行第一个元素的地址。 -
输出:
0x7ffee3b8e9a0
-
7.二维数组指针具体元素地址表示
-
arr[1] + 2
:-
arr[1] + 2
是一个指向int
的指针,表示第二行第三个元素的地址。 -
输出:
0x7ffee3b8e9a8
-
-
*(arr + 1) + 2
:-
*(arr + 1) + 2
等价于arr[1] + 2
,是一个指向int
的指针,表示第二行第三个元素的地址。 -
输出:
0x7ffee3b8e9a8
-
-
&arr[1][2]
:-
&arr[1][2]
是一个指向int
的指针,表示第二行第三个元素的地址。 -
输出:
0x7ffee3b8e9a8
-
8.二维数组指针具体元素的值表示
-
*(arr[1] + 2)
:-
*(arr[1] + 2)
解引用arr[1] + 2
,得到第二行第三个元素的值7
。 -
输出:
7
-
-
*(*(arr + 1) + 2)
:-
*(*(arr + 1) + 2)
解引用*(arr + 1) + 2
,得到第二行第三个元素的值7
。 -
输出:
7
-
-
arr[1][2]
:-
arr[1][2]
直接访问第二行第三个元素的值7
。 -
输出:
7
-
9. 二维数组指针地址的输出
// 行地址
printf("第一行地址: %p\n", (void *)arr);
printf("第二行地址: %p\n", (void *)(arr + 1));
printf("第三行地址: %p\n", (void *)(arr + 2));
// 列地址
printf("第一行第一列地址: %p\n", (void *)arr[0]);
printf("第一行第二列地址: %p\n", (void *)(arr[0] + 1));
printf("第二行第一列地址: %p\n", (void *)(*(arr + 1)));
// 具体元素地址
printf("a[1][2]的地址: %p\n", (void *)(arr[1] + 2));
printf("a[1][2]的地址: %p\n", (void *)(*(arr + 1) + 2));
printf("a[1][2]的地址: %p\n", (void *)&arr[1][2]);
// 具体元素的值
printf("a[1][2]的值: %d\n", *(arr[1] + 2));
printf("a[1][2]的值: %d\n", *(*(arr + 1) + 2));
printf("a[1][2]的值: %d\n", arr[1][2]);
9. 二维数组指针应用
使用二维数组指针迎接财神。