数组指针
数组指针本质上是一种指针,用来存放数组的地址。
p // 是个变量
*p // 与*结合代表是指针变量
*p[] // 此时由于[]的优先级比*高 所以p现在是个数组
(*p)[] // 所以括起来让先与*结合代表是个指针,在与[]结合代表指向数组
(*p)[10] // p是个指针指向一个数组,指向可以存放10个元素的数组
int (*p)[10]// p是个指针指向一个数组,指向可以存放10个元素的数组,并且指向的数组每个元素是int
int (*)[10] 是数组指针类型。
char * arr[5]的地址应该怎么被存放呢?
int main () {
char * arr[5] = {NULL , NULL , NULL , NULL , NULL};
char * (*ptr)[5] = &arr;
/*
解析:
ptr先与*结合代表是一个指针变量,在与[5]结合代表指向一个数组,这个数组
可以存放五个元素,并且ptr指向这个数组的每一个元素是char *
*/
return 0;
}
数组指针的使用
例1:
#include <stdio.h>
int main() {
int arr[10] = { 1 , 2, 3 , 4 , 5 , 6 , 7 , 8, 9, 10 };
int(*ptr)[10] = &arr;
int i = 0;
for (i = 0; i < 10; i++) {
/*
ptr = &arr
两边同时来个解引用:*ptr = *&arr = arr
// 而arr又是数组名,数组名又是首元素地址
*ptr = *&arr = arr = &arr[0]
*ptr + i = &arr[0] + i
*(*ptr + i) = *(&arr[0] + i)
*/
printf("%d " , *(*ptr + i));
}
/*
result: 1 2 3 4 5 6 7 8 9 10
*/
return 0;
}
一维数组使用数组指针的方式绕弯路了,相对比较麻烦,用一级指针指向数组名的方式更方便。数组指针的使用场景一般在二维数组上。
例2:
#include <stdio.h>
int main() {
int arr[3][5] = {
{1 , 2 , 3 , 4 , 5},
{6 , 7 , 8 , 9 , 10},
{11 , 12 , 13 ,14 , 15}
};
int(*ptr)[5] = arr;
int i = 0;
for (i = 0; i < 3; i++) {
int j = 0;
for (j = 0; j < 5; j++) {
/*
解析:
ptr = arr = &arr[0]
// 二维数组名也代表首元素地址,而二维数组的首元素是一维数组
// 所以首元素的地址相当于一维数组的地址给ptr类型刚好对应
ptr + i = &arr[0] + i
// &arr[0] 是第一行的地址 + 1相当于跳过1行 + 2相当于跳过2行
// + i相当于跳过i行
*(ptr + i) = *(&arr[0] + i)
// 如果 i 是 1 的话 相当于*(&arr[0] + 1) = *&arr[1] = arr[1] (i同理)
// 原来是数组的地址第一个解引用相当于把&抵消了,拿到了当前这行的数组名
// 而当前这行的数组名又相当于这行首元素的地址 arr[1] = &arr[1][0]
*(ptr + i) + j = *(&arr[0] + i) + j
// 当 i = 1时 *(ptr + i) = arr[1] = &arr[1][0]
// *(ptr + i) + j = &arr[1][0] + j 代表拿到当前这行的首元素地址在 + j
// 就是当前这行第j个元素的地址
*(*(ptr + i) + j) = *(*(&arr[0] + i) + j)
// 如果 i = 1 , j = 2
// ptr = &arr[0]
// ptr + 1 = &arr[0] + 1 = &arr[1]
// *(ptr + 1) = *&arr[1] = arr[1] = &arr[1][0]
// *(ptr + 1) + 2 = &arr[1][0] + 2 = &arr[1][2]
// *(*(ptr + 1) + 2) = *&arr[1][2] = arr[1][2]
*/
printf("%-3d " , *(*(ptr + i) + j));
}
printf("\n");
}
return 0;
}
解析:
ptr = arr = &arr[0]
二维数组名也代表首元素地址,而二维数组的首元素是一维数组
所以首元素的地址相当于一维数组的地址给ptr类型刚好对应
ptr + i = &arr[0] + i
&arr[0] 是第一行的地址 + 1相当于跳过1行 + 2相当于跳过2行 + i相当于跳过i行
*(ptr + i) = *(&arr[0] + i)
如果 i 是 1 的话 相当于*(&arr[0] + 1) = *&arr[1] = arr[1] (i同理)
原来是数组的地址第一个解引用相当于把&抵消了,拿到了当前这行的数组名
而当前这行的数组名又相当于这行首元素的地址 arr[1] = &arr[1][0]
*(ptr + i) + j = *(&arr[0] + i) + j
当 i = 1时 *(ptr + i) = arr[1] = &arr[1][0]
*(ptr + i) + j = &arr[1][0] + j 代表拿到当前这行的首元素地址在 + j
就是当前这行第j个元素的地址
*(*(ptr + i) + j) = *(*(&arr[0] + i) + j)
如果 i = 1 , j = 2
ptr = &arr[0]
ptr + 1 = &arr[0] + 1 = &arr[1]
*(ptr + 1) = *&arr[1] = arr[1] = &arr[1][0]
*(ptr + 1) + 2 = &arr[1][0] + 2 = &arr[1][2]
*(*(ptr + 1) + 2) = *&arr[1][2] = arr[1][2]