目录
1.使用指针访问数组
1.1数组名的理解
上一篇博客主要讲述的是指向变量的指针,这一篇博客主要分析指针与数组的联系。首先我们先看一段代码:
int *p1=arr;//"arr"代表数组第一个元素的地址
int *p2=&arr[0];
int *p3=&arr;//取出的是整个数组的地址
这一段代码中,第一行与第二行的效果相同,因为在C语言中,大多数情况下,“arr”都代表数组首元素的地址(反例:sizeof 中以及 &arr 中):
(1)lenth=sizeof(arr)/sizeof(arr[0]) 中,“arr”代表的是整个数组。
(2)&arr,这里取出的也是整个数组的地址。
其他情况下,“arr”均代表数组首元素的地址。
1.2使用指针访问数组
int arr[10]={1,2,3,4,5,6,7,8,9,10];
int sz=sizeof(arr)/sizeof(arr[0]);
int *p=arr;//用指针打印数组
int i=0;
for(i=0;i<sz;i++)//sz代表数组的长度
{
scanf("%d",&arr[i]);
}
for(i=0;i<sz;i++)
{
printf("%d ",*(p+i));
}
用解引用逐个访问数组各元素的地址,以达到打印数组每一个元素的效果。
2.数组传参的本质
2.1一维数组传参的本质
还是继续讨论打印一维数组的问题,现在我们不直接用指针打印,而是写一个函数,将数组作为参数传给 print 函数,用 print 函数打印一维数组,代码如下:
我们可以得到以下结论:一维数组传参的本质是传递了数组首元素的地址,所以形参访问的数组和实参访问的数组是同一数组。
所以,形参无论是用 int arr[10],还是 int*p 效果都是相同的。
2.2二维数组传参的本质
2.2.1数组指针
首先区别一下指针数组和数组指针的区别:
指针数组:存放指针变量的数组(例如:int*arr[10] )
数组指针:指向一个数组的指针 数组指针初始化就是(指针变量类型)(*p)[数组元素个数],例如:int*p[10].
2.2.2二维数组数组名
在正式讲二维数组传参之前我们先来讨论一下二维数组数组名的含义。在前面的讲解我们知道,一维数组的数组名代表数组首元素的地址,那二维数组是不是也是如此呢?我们先来看一段代码:
从这段代码不难看出:arr代表的仍然是数组首元素的地址。这与数组在内存中的存储有很大的关系:二维数组在内存中的存储也是连续的,当二维数组的列储存完毕后接着会换一行继续连续存储。
2.2.3二维数组传参
先看下面一段完整代码:
void print(int(*p)[5],int c,int l)
{
int i = 0; int j = 0;
for (i = 0; i < c; i++)
{
for (j = 0; j < l; j++)
{
printf("%d ",*(*(p+i)+j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
int(*p)[5] = arr;
print(p, 3, 5);
return 0;
}
这个代码的输出结果是:
简要分析这段代码:int(*p)[5] 是创建了一个数组指针,指向二维数组的第一个元素,也就是第一个一维数组,并将这个指针作为参数传递到 print 函数去。
在函数内部,*(*(p+i)+j) 的作用是通过地址找到二维数组的各个元素,*(p+i)表示的是arr[][i] , 外部加的 j 是对数组指针进行计算(+1等价于移动一个一维数组),以达到换行的效果。
3.指针数组
3.1指针数组简要示意
前文有介绍,指针数组顾名思义是专门存放指针变量的数组,初始化类似为 int*arr[3]. 简单画图表示就是
这一个指针数组存放的是一个个指针变量,通过指针变量又能访问其他的变量或数组。
3.2指针数组的应用
3.2.1指针数组的概念
回想前面所讲的二维数组传参的本质,如果创建一个变量 int *p=arr ;那么这个变量指向的就是二维数组的第一个元素(即第一个数组),如果我们把这些指向二维数组内数组的指针汇总,装在一个新的数组里面,那么这个新的数组就是指针数组。
还是以 int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} } 这个二维数组举例,这个二维数组可以写成int arr[3][5] = { arr1,arr2,arr3 } 这种形式,也就是前面所说的将二维数组看成几个一维数组的集合这种思想。如果现在创建3个数组指针 p1,p2,p3分别指向 arr1,arr2,arr3,这三个数组指针可以放入一个新的数组内,这个数据就是之前介绍的指针数组。
3.2.2指针数组模拟二维数组
根据3.2.1中的思想,我们先创建三个一维数组以及指向它们的数组指针,再用新数组arr把指针存储起来,然后用两个for循环分别调用一维数组(行数)以及一维数组中的元素下标(列数)来模拟二维数组的输出。代码如下图:
int arr1[5] = { 1,2,3,4,5 };
int arr2[5] = { 2,3,4,5,6 };
int arr3[5] = { 3,4,5,6,7 };
int* p1 = arr1;
int* p2 = arr2;
int* p3 = arr3;
int* arr[3] = { p1,p2,p3 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}