在不断学习和编码中,渐渐发现c指针越来越重要了,自己对指针的理解也越来越深刻。借此系列来总结我对c指针的理解,我会多用画图的方式(较生动形象)增加各位对指针的理解,希望能让大家有所收获,更上一层楼
首先,希望大家在学习使用指针时能做到以下一点
每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?(重点注意)
在开始详细了解指针前,我们应该先了解一下指针的本质。
我们知道,将指针打印出来,是一串数字,其实就是内存中最小单元的编号——也就是地址。所以指针可以约等于地址。而我们口语中常说的指针其实是指针变量的意思,本质上是一个变量,存放的是地址。
总结:指针其实就是地址,而口语中的指针常指指针变量,本质为变量。
指针和变量内存的对比?为什么要有不同类型的指针呢?
我们都知道,不同类型的变量在内存中所占的大小不同。变量有char,int,float,double等等类型,所占字节不同,而对应的指针char*,int*,float*,double*所占字节是不是也应该理所当然的不同呢?
如图所示,结果是出人意料的,尽管指针的类型不同,但是他们相应的所占字节大小却是一样的,都是四个字节或者八个字节。这不禁引人思考,既然大小都一样,何必搞那么多种不同类型的指针呢,一种不是效率更高?我们不妨实践一下
通过内存中我们可以得知这里a的值被改为0了
而当我们用char指针呢
16进制下只有一个字节被改了
我们可以推测,指针的类型不同,对结果的改变是不同的
由此我们可以大胆推测得知,指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
总结:指针的类型决定了,对指针解引用的时候有多大的权限
指针的运算
指针+-整数:即(地址+-整数),结果也就是往前往后移动整数个指针类型单位的地址,得到到还是地址。
指针-指针:结果为两指针中元素的个数(语法规定)
指针的关系运算:指针可以比较大小,但要符合相应的规定——允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。可能干说有点抽象,下图展示可能更好理解。
指针和数组
我们看一个例子
#include<stdio.h>
int main()
{
int arr[10]={0};
printf("%d",arr);
printf("%d",&arr[0]);
return 0;
}
结果为:
可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。(2种情况除外)
1.sizeof(arr)——代表计算整个数组所占内存大小,单位为字节。
所以我们可以用sizeof(arr)/sizeof(arr[0])来计算整个数组有多少个元素
2.&arr,取得是整个数组的地址,而不是数组首元素的地址,若&arr+1则跳过整个数组。
既然可以把数组名当成地址存放到一个指针中,我们使用指针来访问一个数组就成为可能。
#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr)/sizeof(arr[0]);//计算数组元素个数/数组长度
for(i=0; i<sz; i++)
{
printf("&arr[%d] = %p <====> p+%d = %p\n", i, &arr[i], i, p+i);
}
return 0;
}
是不是生动形象展示了指针和数组之间的关系呢?
每个数组元素都有相应的地址,通过指针加减整数再解引用,不断循环进行访问,最终将每一个数组元素都打印出来了 。
以上的指针其实都是一级指针,那么有没有二级指针呢?答案是显然的,二级指针是存在的。
二级指针,其实也是一个指针变量,不过存储的是一级指针变量的地址罢了
#include<stdio.h>
int main()
{
int a=1;
int*p1=&a;
int**pp1=&p1
int***ppp1=&pp1;
return 0;
}
而往上的三级指针,存储的也就是二级指针变量的地址
以此类推,n级指针存储n-1级指针变量的地址(当n>1的时候)
指针数组
我们知道数组的类型也有很多种,比如整形数组,字符数组等等,存储不同的变量
既然指针变量也是变量,那么数组是不是顺理成章的也可以存储它呢?
答案是显然的,存储指针的数组,就叫指针数组
表现形式:int*parr【10】——此处有运算符的优先级,parr先和【】进行结合,说明parr是数组,去掉数组名parr后,剩下的int*【10】就是数组里的元素类型了。
上图就是指针数组的本质,只是听起来高大上了一点。
数组指针
当我们存储int类型地址时有int*接受,存储char类型地址时有char*接收,当我们存储整个数组的地址时,是不是也理所当然要有一个指针去接收呢——那就是和指针数组听起来很相似的数组指针啦。数组指针,顾名思义就是数组的指针,本质上是一个指针。
表现形式:
#include<stdio.h>
int main()
{
int arr[3]={1,2,3};
int (*p)[3]=&arr;
return 0;
}
为了防止p先和【】运算符结合,用()让p与*先结合,说明p为一个指针,指向一个有3个int类型的元素的数组,而p存储整个数组的地址。
本篇内容就先介绍到这里,希望画图的方式能让大家更好了解指针,下一章会继续介绍,谢谢大家观看!