指针数组:
本质依然是数组,只是数组中存放的元素都是指针。就比如好孩子,好只是修饰词,无论他好不好,他都是孩子
#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