目录
- 1. 数组名的本质
- 2. 使用指针访问数组
- 3. 一维数组传参的本质
- 4. 二级指针
- 5. 指针数组
- 5.1 指针数组模拟二维数组
正文开始。
1. 数组名的本质
数组名代表着这个数组中第一个元素的地址
例如:
int arr[4] = { 1,2,3,4 };
int *p1 = &arr[0];
int *p2 = arr;
上述代码中指针变量p1和p2所存储的地址是相同的。
数组名代表着数组中元素首元素的地址,但有两个特例需要特别关注:
- sizeof(arr_name):sizeof 中单独放数组名,这里的数组名代表着整个数组,计算的是整个数组的大小,单位是字节。
- &arr_name:这里的数组名表示的整个数组,取出的是整个数组的地址
除此之外,在其他任何地方使用数组名,它都表示首元素的地址。
需要注意的是,整个数组的地址和首元素的地址是有所不同的。整个数组的地址所指向的对象是一个自定义的数组类型;而首元素的地址所指向的对象是首元素的类型。
例如:
可以看到,上述代码中,&arr所指向的对象类型为int [5],大小为20个字节;而arr所指向的对象类型为int,大小为4字节。
2. 使用指针访问数组
理解了数组名的本质,那我们就可以通过指针来访问数组了。
#include <stdio.h>
int main()
{int arr[5] = { 0 };int size = sizeof(arr) / sizeof(arr[0]);int* p = arr;//p == arr == &arr[0]for(int i = 0; i < size; i++){scanf("%d", p + i);//p + 1 == arr + i == &arr[0] + i == arr[i] == p[i]}for(int i = 0; i < size; i++){printf("%d ", *(p + i));}return 0;
}
运行结果:
3. 一维数组传参的本质
我们时常需要将数组作为参数传递给函数,下面来讨论下一维数组传参的本质。
#include <stdio.h>
void Num(int arr[10])
{int size = sizeof(arr);printf("%d", size);
}int main()
{int arr[10] = { 0 };Num(arr);return 0;
}
32位环境下运行结果:
64位环境下运行结果:
在上述代码第11行调用函数时,函数的参数为arr,这里代表着该数组首元素的地址,所以传递进函数的参数实际上是一个地址。
在函数定义时,用到了void Num(int arr[10]),其中的[10]只是一个形式上的声明,可以理解为告诉开发人员这是一个存放了十个元素的数组。
既然传入的参数本质上是一个地址,那我们当然也可以在定义函数的时候,就将参数设置为指针,例如上文代码等同于:
#include <stdio.h>
void Num(int *p)
{int size = sizeof(p);printf("%d", size);
}int main()
{int arr[10] = { 0 };Num(arr);return 0;
}
4. 二级指针
我们都知道,指针变量就是用来存放所指向对象的地址,那指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里呢?答案就是二级指针
#include <stdio.h>
int main()
{int a = 5;//一级指针,存放变量 a 的地址int* p = &a;//二级指针,存放变量 p 的地址int** pp = &p;//指针的运算//一级指针解引用,*p == a == 5int b = *p;//二级指针解引用,*pp == p,**pp == a == 5int* c = *pp;int d = **pp;return 0;
}
这里只对二级指针做演示,按照二级指针的定义,以此类推,就可以得出多级指针的用法,这里不再赘述。
5. 指针数组
指针数组,究竟是指针呢,还是数组呢?
我们类比一下,韭菜盒子,到底是韭菜呢,还是盒子呢,很显然,它指的是韭菜馅的盒子。
那指针数组呢?是存放指针的数组。
图例:
5.1 指针数组模拟二维数组
#include <stdio.h>
int main()
{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* parr[3] = { arr1,arr2,arr3 };int i = 0;int j = 0;for(i = 0; i < 3; i++){for(j = 0;j < 5; j++){printf("%d ",parr[i][j]);//可理解为(parr[i])[j]//例如parr[1][3]//parr[1][3] == (parr[1])[3] == arr2[3] == 5}printf("\n");}return 0;
}
运行结果:
图解:
上述代码实现了二维数组的效果,但其本质上并不是二维数组,因为每一行在内存中并非是连续存储的,而二维数组的元素在内存中是连续存储的。
完