C语言数组指针(指向数组的指针)详解
数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。
定义数组时,要给出 "数组名"和"数组长度", 数组名可以认识是一个"指针",它指向数组的第0个元素。
在C语言中我们将数组的"第0个元素"的地址 称为"数组的首地址"。
//下面的例子演示了如何以指针的方式遍历数组元素:
#include<stdio.h>
int main()
{
int kangkang[] = {99,88,66,55,44,33,222};
int len = sizeof(kangkang)/sizeof(int); //求数组的长度
int i;
for(i=0;i<len;i++)
{
printf("%d",*(kangkang+i)); // *(kangkang+i) 等价于kangkang[i]
}
printf("\n");
return 0;
}
结果:
99 88 66 55 44 33 222
解析:
1. 本程序的第5行代码用来求 数组长度,sizeof(kangkang)会获取"整个数组所占的字节数",
sizeof(int)会获取到"一个数组元素所占的字节数",它们相除的结果就是"数组包含的元素个数"即数组长度。
2. 本程序的第8行代码中 我们使用了 *(kangkang+i)这个表达式,kangkang是数组名,指向数组的第0个元素。
它表示"数组首地址", kangkang+i指向数组的第i个元素, *(kangkang+i) 表示获取第i个元素的数据,等价于kangkang[i]
//我们也可以定义一个指向数组的指针
例如:
int arr[] = { 99, 15, 100, 888, 252 };
int *p = arr;
arr 本身就是一个指针,可以直接赋值给指针变量 p。arr 是数组第 0 个元素的地址,所以int *p = arr;
也可以写作int *p = &arr[0];
也就是说 arr、p、&arr[0] 这三种写法都是等价的,它们都指向数组第 0 个元素,或者说指向数组的开头。
如果一个指针指向了数组,我们就称它为"数组指针"
数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关,上面的例子中,p 指向的数组元素是 int 类型,所以 p 的类型必须也是int *。
反过来想,p 并不知道它指向的是一个数组,p 只知道它指向的是一个整数,究竟如何使用 p 取决于程序员的编码。
更改上面的代码,使用数组指针来遍历数组元素:
#include<stdio.h>
int main()
{
int kangkang[] = {99,88,66,55,44,33,222};
int i ,*p = kangkang,len = sizeof(kangkang)/sizeof(int);
for(i=0;i<len;i++)
{
printf("%d",*(p+i));
}
printf("\n");
return 0;
}
"数组"在内存中 只是 数组元素的简单排序,没用开始和技术标志,在求数组的"长度"时不能使用sizeof(p)/sizeof(int),因为p只是一个指向int类型的指针。
编译器并不知道它到底指向的是"一个整数"还是"一系列整数(数组)",所以 sizeof(p) 求出来的是 p这个指针变量"本身所占用的字节数",而不是整个数组的字节数。
也就是说,根据数组指针"不能逆推出"整个数组元素的个数,以及数组从哪里开始、到哪里结束等信息。不像字符串,数组本身也没有特定的结束标志,如果不知道数组的长度,那么就无法遍历整个数组。
引入数组指针后,我们就有两种方案来访问数组元素了,一种是使用下标,另外一种是使用指针。
1. 使用下标
也就是采用 arr[i] 的形式访问数组元素。如果 p 是指向数组 arr 的指针,那么也可以使用 p[i] 来访问数组元素,它等价于 arr[i]。
2. 使用指针
也就是使用 *(p+i) 的形式访问数组元素。另外数组名本身也是指针,也可以使用 *(arr+i) 来访问数组元素,它等价于 *(p+i)。
不管是数组名还是数组指针,都可以使用上面的两种方式来访问数组元素。
不同的是,数组名是常量,它的值不能改变,而数组指针是变量(除非特别指明它是常量),它的值可以任意改变。
也就是说,数组名只能指向数组的开头,而数组指针可以先指向数组开头,再指向其他元素。
更改上面的代码,借助自增运算符来遍历数组元素:
#include <stdio.h>
int main(){
int arr[] = { 99, 15, 100, 888, 252 };
int i, *p = arr, len = sizeof(arr) / sizeof(int);
for(i=0; i<len; i++){
printf("%d ", *p++ );
}
printf("\n");
return 0;
}
结果:
99 15 100 888 252
本程序第 8 行代码中,*p++ 应该理解为 *(p++),每次循环都会改变 p 的值(p++ 使得 p 自身的值增加),以使 p 指向下一个数组元素。
该语句不能写为 *arr++,因为 arr 是常量,而 arr++ 会改变它的值,这显然是错误的。
//关于数组指针的谜题:
假设p是针向数组kangkang中第n个元素的指针, 那么 *p++、*++p、(*p)++ 分别是什么意思?
1. *p++等价于*(p++),表示"先取得第n个元素的值"再将p指向下一个元素。
2. *++p等价于*(++p),表示"先进行++p的运算,使得p的值增加",指向下一个元素,整体上相当于*(p+1),所以会获得第n+1个数组元素。
3. (*p)++就非差简单了,它"先取得第n个元素的值",再对该元素的值+1,假设p指向第0个元素,并且第0个元素的值为99,执行完该语句后,第0个的值就变成100.