既然我们知道指针与地址和地址上的数据紧密相连,而且一切数据都有相应的地址,那么指针是不是可以应用在很多方面?
运用指针之前先来看一下指针的运算(加法、减法、比较运算)。
指针变量保存的是地址,而地址本质上是一个整数,所以指针可以进行部分运算,例如加法、减法,比较等。
请看下面的代码:
#include<stdio.h>
int main()
{
int a=10,*pa=&a,*paa=&a;
double b=99.9,*pb=&b;
char c='@',*pc=&c;
printf("&a=%#X,&b=%#X,&c=%#X\n",&a,&b,&c);
printf("pa=%#X,pb=%#X,pc=%#X\n",pa,pb,pc);
pa++;pb++;pc++;
printf("pa=%#X,pb=%#X,pc=%#X\n",pa,pb,pc);
pa-=2;pb-=2;pc-=2;
printf("pa=%#X,pb=%#X,pc=%#X\n",pa,pb,pc);
if(pa==paa)
{
printf("%d\n",*paa);
}
else
{
printf("%d\n",*pa);
}
return 0;
}
运行结果如下:
从运算结果可以看出:pa、pb、pc 每次加 1,它们的地址分别增加 4、8、1,正好是 int、double、char 类型的 长度;减 2 时,地址分别减少 8、16、2,正好是 int、double、char 类型长度的 2 倍,所以进行指针的运算时,实际上进行的是地址的运算,并且单位长度是指针数据类型的长度。
这也不难理解为什么是以数据类型长度为单位长度进行计算的:
如图:
![](https://i-blog.csdnimg.cn/blog_migrate/080a5cdf20822ac38dfee90de0bd315c.png)
若直接在地址上加1,就没有意义了。
但是,即使是使用者连续定义的变量,也不一定在地址上连续排列;
如下:
#include<stdio.h>
int main()
{
int a=1,b=2,c=3;
int *p=&c;
int i;
for(i=0;i<8;i++)
{
printf("%d",*(p+i));
}
return 0;
}
输出结果如下:
如图所示,a,b,c并不是连续存储的,所以并不能通过指针获取下一个变量的地址。
指针变量除了可以参与加减运算,还可以参与比较运算。当对指针变量进行比较运算时,比较的是指针变量本身的 值,也就是数据的地址。如果地址相等,那么两个指针就指向同一份数据,否则就指向不同的数据。
下面我们看一下数组指针(指向数组的指针)
:
注:数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元 素在内存中是连续排列的,整个数组占用的是一块内存。
如果一个指针指向了数组,我们就称它为
数组指针
。
指针用来可以输出数组中的元素:
#include<stdio.h>
int main()
{
int arr[]={99,15,100,888,252};
int len=sizeof(arr)/sizeof(int);//求数组长度
int i;
for(i=0;i<len;i++)
{
printf("%d ",*(arr+i));//*(arr+i)等价于arr[i]
}
printf("\n");
return 0;
}
运行结果如下:
sizeof(arr) 会获得整个数组所占用的字节数,sizeof(int) 会获得一个数组元素所占 用的字节数,它们相除的结果就是数组包含的元素个数,也即数组长度。
arr 是数组名,指向数组的第 0 个元素,表示数组首地址, arr+i 指 向数组的第 i 个元素,*(arr+i) 表示取第 i 个元素的数据,它等价于 arr[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+i));
}
printf("\n");
return 0;
}
结果如下:
数组首地址可以认为是一个指针(但并不是总等价),所以对上述*p赋值时arr前不加‘&’。
也可以让p指向数组中非首地址上的其他元素,
例如让p指向数组中第二个元素:
#include<stdio.h>
int main()
{
int arr[]={99,15,100,888,252};
int *p=&arr[2];//也可以写成int*p=arr+2;
printf("%d,%d,%d,%d,%d\n",*(p-2),*(p-1),*p,*(p+1),*(p+2));
return 0;
}
结果如下:
现在我们已经有了两种方法来访问数组中的数据:
1.使用下标
也就是采用 arr[i] 的形式访问数组元素。如果 p 是指向数组 arr 的指针,那么也可以使用 p[i] 来访问数组元素, 它等价于 arr[i]。
2.使用指针
也就是使用 *(p+i) 的形式访问数组元素。另外数组名本身也是指针,也可以使用 *(arr+i) 来访问数组元素,它等价 于 *(p+i)。
注意:
数组名是常量,它的值不能改变;而数组指针一般是变量,它的值可以改变。也就是说,数组名只能指向数组的开头,而数组指针可以先指向数组开头,再指向其他元素。