前言
前面的文章讲了指针的一些基本内容,这里我们来讲一下数组指针与指针数组,数组指针是指针运用的一个明显体现,准确来说是通过指针访问内存地址的具体体现
一、一维数组的指针
首先,我们先来看一段代码
#include <stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = &arr[0];
int* p = arr;
printf("pa -> %p\n", pa);
printf("p -> %p\n", p);
return 0;
}
在上述结果中我们发现,数组arr的首元素地址与arr这个数组的名字是一样的,所以数组名就是首元素的地址
同时在【C语言】自定义类型数据-数组这篇文章中我们说过,数组是一个连续的内存空间,所以,我们可以通过指针的运算来逐一访问数组的元素,请看下面的代码
#include <stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = &arr[0];
for (int i = 0; i < 10; i++) {
printf("%d ", *(pa + i));
}
return 0;
}
arr是首元素地址的特殊情况
一、&arr
我们上面说了,数组名arr就是数组arr首元素的地址,那么当我们&arr时,得到的会是什么呢?那让我们看一下下面的代码
#include <stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = &arr[0];
printf("pa -> %p\n", pa);
printf("parr -> %p\n", &arr);
printf("pa + 1 -> %p\n", pa + 1);
printf("parr + 1 -> %p\n", &arr + 1);
return 0;
}
结果如下:
pa -> 000000D1FA16F5D8
parr -> 000000D1FA16F5D8
pa + 1 -> 000000D1FA16F5DC
parr + 1 -> 000000D1FA16F600
我们可以发现,pa与pa + 1相差了4个字节,也就是一个整形,但是parr与parr + 1相差了40个字节,隔了一个数组的大小,也就是说,&arr得到的parr是整个数组的地址,当parr + 1时指针会走过一个数组,所以此时的arr不是首元素的地址,而是整个数组
二、sizeof(arr)
我们先看代码
#include <stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = &arr[0];
printf("sizeof(pa) -> %zd\n", sizeof(pa));
printf("sizeof(arr) -> %zd\n", sizeof(arr));
return 0;
}
这里我们可以发现,sizeof(arr)得到的并不是地址的大小,而是arr数组的大小,也就说sizeof(arr)中的arr并不代表着首元素的地址,而是代表整个数组的
二、二维数组指针
我们上面很详细地介绍了一维数组的指针,接下来我们介绍一下二维数组的指针,对于二维数组我们可以如此定义:
类型 (*ptr)[M] = arr;
这里的类型也就是二维数组的元素的数据类型,而ptr则是指针的名称,M则是一行数组的元素数量,我们看下面的代码
#include <stdio.h>
int main() {
int arr[2][5] = {1,2,3,4,5,6,7,8,9,10};
int(*pa)[5] = arr;
return 0;
}
这里我们定义了一个行为2列为5的二维数组指针变量,那么,这个指针变量究竟是什么呢?让我们继续看下面的代码
#include <stdio.h>
int main() {
int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
int(*pa)[5] = arr;
printf("*pa -> %p\n", *pa);
printf("&arr[0] -> %p\n", &arr[0]);
printf("&arr[0][0] -> %p\n", &arr[0][0]);
printf("\n");
printf("*(pa + 1) -> %p\n", *(pa + 1));
printf("&arr[1] -> %p\n", &arr[1]);
printf("&arr[1][0] -> %p\n", &arr[1][0]);
printf("\n");
printf("**pa -> %d\n", **pa);
return 0;
}
其实我们根据结果可以发现二维数组的指针是一个二级指针,而且存放的是一个行数组的指针(arr[0]),也就是首元素地址,当我们进行(pa + 1)时,指针变成了第二行数组的指针(arr[1]),也是第二行数值的首元素地址,我们可以简单用图表示*
所以通过指针我们也可以对二维数组进行访问
三、指针数组
我们之前说过,数组是一种基本的数据结构,用于存储相同类型的多个值,当然相同类型的多个值也包括指针类型,所以我们可以定义一个数组来存储我们的指针,请看下面的代码
#include <stdio.h>
int main() {
int* ptrarr[3] = { 0 };
int arr[3] = { 1,2,3 };
ptrarr[0] = &arr[0];
ptrarr[1] = &arr[1];
ptrarr[2] = &arr[2];
for (int i = 0; i < 3; i++) {
printf("ptrarr[%d] -> %p\n", i + 1, ptrarr[i]);
}
return 0;
}
这里我们定义了一个整形类型指针数组用来储存我们的整形指针,定义指针类型的方法与定义普通类型的数组是一样的,所以我就不再多讲啦!
End
对于指针的所有内容,博主只能到这个地步啦,谢谢大家的阅读,希望我的文章对大家有帮助!