指针数组:
本质依然是数组,只是数组中存放的元素都是指针。就比如好孩子,好只是修饰词,无论他好不好,他都是孩子
#include<stdio.h> int main() { int arr[10] = { 0 };//整型数组 char ch[5] = { 0 };//字符数组 int* pr[4];//存放整形指针的数组----指针数组 char* pr1[5];//存放字符指针的数组----指针数组 return 0; }
现在我们通过一个示例感受一下这个过程:
#include<stdio.h> int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 2,3,4,5,6 }; int arr3[] = { 3,4,5,6,7 }; int* parr[] = { arr1,arr2,arr3 };//将数组arr1/arr2/arr3存放到指针数组parr中 int i; for (i = 0; i < 3; i++)//对指针数组中的元素进行访问 //也就是对arr1/arr2/arr3的首元素地址进行访问 { int j = 0; for (j = 0; j < 5; j++)//对每个数组中的元素进行访问 { printf("%d ", *(parr[i]+j));//parr[i]输出指针数组的元素等价于输出每个元素的首地址 //+j之后会对三个数组中的元素进行访问 } printf("\n"); } return 0; }
输出结果如下所示:
数组指针:
本质依然是指针,只不过为指向数组的指针,存放数组的地址。
那该如何定义呢?首先,回忆我们之前学过的整形指针和字符指针的定义方法
int* p = NULL;//p是整形指针---指向整形的指针--可以存放 char* pc = NULL;//pc是字符指针---指向字符的指针
其次,我们之前还学过对任意数组有:
int arr[10]={0}; //arr/&arr[0]为首元素地址 //&arr为整个数组的地址
那么数组指针是不是可以这样表示?
下面那个是数组指针?
1:int* p1[10]; 2:int(*p2)[10];
正确答案是2,那么1为什么不是呢?原因是[]的优先级高于*,对于第一种,p1会优先和[]进行结合,这里的p就成为数组了,但2将p2括起来,强制使p先和进行结合,这里的p是指针。
下面再通过一道题考考你:
如下所示代码中的pa应该怎么进行定义呢?
char* arr[5]; pa = &arr;
采访了一一些同学后,有以下三种答案,那么到底哪种是正确的呢?
A:char(*pa)[5]; B:char* (*pa)[5]; C:char(**pa)[5];
正确答案为同学B的,下面我们来说说该怎么正确定义:
先对代码进行分析:
char* arr[5];//定义字符指针数组,元素个数为5个 pa = &arr;//将数组arr的地址存放到pa中
我们想定义一个数组指针,那么首先得指明pa是一个指针即为pa,又因为上文我们提到,[]的优先级高于,因此我们赶快将*pa括起来,即为(*pa),又因为arr本身是数组,那么指针pa需要指明数组的元素,即为(*pa)[5],最后在最面加上数组的类型,可以类比整形指针的定义方法。
数组名VS&数组名:
数组名代表数组首元素地址,&数组名代表整个数组的地址。
下面我们通过一段代码验证一下:
arr+1跳过的字节长度为一个int,而&arr+1跳过的字节长度为10个int
一维数组与数组指针的结合使用:
举例:
#include<stdio.h> int main() { int arr[10] = { 2,34,51,2,3,10,9,11,21,0 }; int(*pa)[10] = &arr; int i; for (i = 0; i < 10; i++) { printf("%d ", (*pa)[i]); //printf("%d ",*(*pa+i)); //(*pa)[i],*pa==arr先对指针进行解引用操作,再找数组中的元素 } return 0; }
2 34 51 2 3 10 9 11 21 0
看到这里,有的小伙伴会觉得干嘛要搞得这么麻烦啊?直接用指针输出就可以了啊
#include<stdio.h> int main() { int arr[10] = { 2,34,51,2,3,10,9,11,21,0 }; int* p = arr; int i; for (i = 0; i < 10; i++) { printf("%d ", *(p+i)); } return 0; }
是的,这样确实也能很好的输出,但数组指针的实用性并不体现在一维数组,而是二维及二维以上数组,下面我们通过示例验证:
对于二位数组元素的输出,常规方法:
#include<stdio.h> void print1(int arr[3][5], int x, int y)//传递数组形式,行,列,参数是数组 { int i, j; for (i = 0; i < x; i++) { for (j = 0; j < y; j++) { printf("%d ", arr[i][j]); } printf("\n"); } } int main() { int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,0},{0,9,8,7,6} }; print1(arr, 3, 5);//传递数组名,行,列 return 0; }
使用数组指针的方法:
#include<stdio.h> void print2(int(*p)[5], int x, int y)//参数是指针,传递的为第一行的地址 { int i = 0; for (i = 0; i < x; i++) { int j = 0; for (j = 0; j < y; j++) { printf("%d ", *(*(p + i) + j));//*(p+i)找到该二维数组的确定的行,+j之后才能找到每行的每个元素 //printf("%d ", *(p + i) [j]); } printf("\n"); } } int main() { int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,0},{0,9,8,7,6} }; print2(arr, 3, 5); return 0; }
怎么理解二维数组呢?
最后我们通过示例区分一下这几个概念:
int arr[5];//arr是含有5个元素的整型数组 int* parr1[5];//parr1是一个数组,数组有10个元素,每个元素的类型是int*,parr1是指针数组 int(*parr2)[10];//parr2是一个指针,该指针指向了一个数组 //数组中有10个元素,其类型为int,parr2为数组指针 int(*parr3[10])[5];//parr3是一个数组,该数组有10个元素,每个元素是一个数组指针 //该数组指针指向的数组有5个元素,每个元素是int