指针是什么
指针和指针类型
野指针
指针运算
指针和数组
二级指针
指针数组
指针是什么
指针是内存中最小单元的编号也就是地址
我们口头的指针指的是指针变量;
int a=0;
int*pa=&a;
a是整型int类型有4个字节;
pa取得是a的第一个字节的地址(较小的地址)
pa是指针变量,这种变量专门存放地址的;
内存上有编号吗? 没有
都是通过电信号产生二进制序列作为编号找第几个内存空间
32位机器的内存会产生2^32种地址;
一个地址管理一个内存单元,所有可以管理2^32个字节
bit 8
byte 1024
kb 1024
mb 1024
gb 1024
tb 1024
...
2^32byte==4G
一个编号有32个bit位 就是4个byte 所以说地址需要4个字节存储
指针类型
如图
这种类型是有意义的
1.类型决定了,指针解引用时一次性访问几个字节
![](https://img-blog.csdnimg.cn/img_convert/b2cb17ad3b44b120e931cfdd9a9a5f95.png)
2.决定了指针偏移多少个字节(指针的步长)
![](https://img-blog.csdnimg.cn/img_convert/1f3db0377c3eb46bd065be689b8fac34.png)
字符char指针加1,跳过1个字节
整型int指针加1,跳过4个字节
其类型数据并不是只能被其类型指针控制,如图
![](https://img-blog.csdnimg.cn/img_convert/5b9a2230d9bb2b3105a90d8972be7065.png)
可以发现int类型数据被char类型指针一个一个字节修改;
ps强制类型转换 int a char b 数较小(127~-128)时,a b相等 较大时数据改变
浮点强制类型转换为整型 会精度丢失
会发现指针类型的意义在于
指针变量不同的类型,其实提供了不同的视角来看待和访问内存
char*---一次访问1个字节,+1跳过1个字节
int*-----一次访问4个字节,+1跳过4个字节
类型也会对解引用时操作,指针类型区分对几个字节空间的操作
int 解引用4个字节
char解引用1个字节
野指针
概念:野指针就是指指针指向未可知的(随机的、不确定的、没有明确限制的)
野指针成因
指针未初始化
int*p;
*p=20;
p里面为随机值,*p=20;我们把20放到随机值里,这是有问题的
所以指针要有个明确指向,才可以解引用操作;
指针越界访问
在使用未申请的地址
int main()
{
int*p=NULL;
*p = 10;//NULL禁止写入数据
return 0;
}
内存释放
内存开辟后返回地址后内存销毁
![](https://img-blog.csdnimg.cn/img_convert/850592c1e6c3098060192b67f879baa9.png)
当test函数结束时,内存归还操作系统,返回的地址是野指针不可用其
访问其空间;
看代码
int* fun()
{
int a = 10;
return &a;
}
int main()
{
int* p = fun();
printf("%d\n", *p);
return 0;
}
打印结果的确是10 ,只是因为地址内数据为被其他变量使用;
如果是
int* fun()
{
int a = 10;
return &a;
}
int main()
{
int* p = fun();
printf("%d\n", *p);
printf("123456\n");
printf("%d\n", *p);
return 0;
}
再一次调用一个函数printf,开辟栈帧,将前一个函数fun栈帧数据覆盖此时&a地址的值将改变
如果规避野指针
指针初始化 --NULL或&变量
注意不可以对空指针NULL访问数据;
在使用指针时尽量判断if(指针变量!=NULL)
小心指针越界
指针指向的空间free后,指向空指针
int*p=&a;
free(p);
p=NULL;
避免返回临时变量的地址
int* fun()
{
int a = 10;
return &a;
}
int main()
{
int* p = fun();//不要使用这样的临时变量的地址
printf("%d\n", *p);
return 0;
}
5.检查指针有效性
void fun(char*p)
{
if(p!=NULL)
{
//使用指针;
}
else if(p==NULL)
{
//不使用该指针;
printf("p为空指针,函数直接结束");
return;
}
}
PS:程序运行时有些内存是操作系统要使用的(内核区域),用户不可使用的,被规定的,NULL规定不可访问内存
指针运算
指针+-整数
指针-指针
指针的关系运算
指针+-整数
![](https://img-blog.csdnimg.cn/img_convert/01af1e3807cde350f4f8eebd76f5e663.png)
先解引用vp放入0;然后再指针偏移vp++
指针-指针
前提,两个指针指向同一块空间;
int arr[10]={0};
prntf("%d",&arr[9]-&arr[0]);//结果为
指针减去指针得到的是连个指针的元素个数
指针的关系运算
看图
![](https://img-blog.csdnimg.cn/img_convert/6757f0a33fc5853cdd2c528b39f211aa.png)
指针比较大小,vp>values[0];再去调整vp,调整后再赋值
如果--vp直接放入for括号内导致先赋值再去调整,会出现2个错误,1.对未开辟空间的使用2.values[0]无法被赋值就结束循环;
看简化代码将--vp放入的正确写法
![](https://img-blog.csdnimg.cn/img_convert/acc3231c832d97cce678333d79ba6526.png)
但会违背标准定义
标准规定
![](https://img-blog.csdnimg.cn/img_convert/5d33e04987683caa68b2488dba1047a4.png)
可以向后(数组最后元素之后)越界地址比较,不可以向前(数组第一个元素之前)越界地址比较,注意无论前后都不可访问这种指针内的数据,会造成越界访问,只能进行地址比较;(看一眼银行,和抢银行);
指针和数组
1.指针和地址是不同的对象
指针(指针变量)是一种变量,存放地址用的,大小为4/8字节的(固定的)
数组是一种相同类型元素的集合,是可以放多个元素的,大小取决于元素个数和元素类型
看一个栗子
2.数组的数组名是数组首元素地址(除了sizeof(数组名)和&数组名);
int main()
{
int arr[10] = { 0 };
int* pa = arr;
int i = 0;
for (i = 1; i <= 10; i++)
{
*pa = i;
pa++;
}
pa = arr;
for (i = 0; i < 10; i++)
{
printf("%d ", pa[i]);
//printf("%d ", *(pa + i));
//printf("%d ", *(i+pa));
//printf("%d ", i[pa]);
}
return 0;
}
说明[]是操作符
i和arr是两个操作数而已
使用arr[i]==i[arr];
二级指针
二级指针是什么?
用来保存指针的地址的
//指针基本使用
int a=10;
int*pa=&a;
*pa=20;//改变a的值
printf("%d",a);--->打印为20
取pa的地址
//指针基本使用
int a=10;
int* pa=&a; //pa是int*
int** ppa=&pa;//ppa是int**
*pa=20;//改变a的值
printf("%d",a);--->打印为20
pa的第一个星告诉我pa是个指针 剩余的为int被指向的整型类型
ppa的第一个星告诉我ppa是个指针 剩余的为int*被指向的整型指针类型
所以pa是一级指针
ppa是二级指针
![](https://img-blog.csdnimg.cn/img_convert/c4c482b1b1504752914b79fed9539ee0.png)
用*ppa改变a,首先*ppa找到pa,在解引用**ppa找到*pa的a
总结二级指针是用来保存一级指针的地址
指针数组
是数组还是指针
是数组!
char arr[5];//存放char类型的数组
int arr[5];//存放int类型的数组
int* arr[5]={&a,&b,&c,&d,&e};
![](https://img-blog.csdnimg.cn/img_convert/1586e82efc211a64f19ccb2f8d528be1.png)