指针是一个变量,里面存了地址。
而地址是存在指针里面的(这就是地址与指针的关系)
把内存当成一个公寓;每一个字节是一户,每一户的门牌号就是地址(指针)
地址由32或64的二进制位组成(在打印的时候(用%p打印)可能会以别的进制显示(ex,16进制))
指针变量
Ex
int a = 0;
int * p = &a;
Int(指针变量p指向的类型) *(说明p是一个指针变量)
p(指针变量存放a的地址)
指针变量的大小有由环境决定(x86下是4个字节 , x64下8个字节)
指针变量类型的意义:
1.加减中的应用 : 在int类型的指针加减时每一份是4个字节, 而char类型每份是1个字节,其他的类比
因此指针的类型决定了指针向前或者向后走一步有多大(距离)
特殊的指针类型:
一. viod指针类型:
void的类型的指针可以接收各种类型的地址,一般将其用在函数参数的部分
以达到一个广泛编程的效果
注意:void的类型因为类型是不定的所以无法进行 指针运算和解引用
二. 数组的指针类型变量:
原理:优先级: [ ] ,(),(.)> ++,-- > * > +,-{可见+,-的优先级比较低,( . )
操作符的优先级甚至比肩括号家族}
格式举例: int (*p) [10] = &arr( 指向整个数组因此就要取出整个数组的地址)
分析: *使p为指针类型,p指向的是一个整形数组( 【10】是数组的特征 )
注意:int *p1[10] =(这个没有小括号调整优先级,则这个意思是)
p1数组的10个元素是整形指针类型(所以是数组指针)
作用:这种的数组指针变量类型至少要用在二维数组中,它可以当二维数组的首元素
用来函数形参的创建( 二维数组的元素是一维数组,函数形参创建不是正好要一个首元素地址吗 )下图的int (*p)[5] = int arr[][]
三.函数指针类型:
格式举例:int (*pf3) ( int x , int y )
分析: int 是函数的返回类型 , 由于后边是函数的特征所以( *pf3 )是指向函数的指针 pf3为变量名 , ( int x , int y )是函数参数类型
四.函数指针数组:
一个数组里面的元素、是函数指针类型
格式举例:int ( * parr1[ 3 ] )( )
分析:parr1【3】是数组,它的类型是 int (*)()【由数组三要素来判断】
作用:可以减少赘余
指针的运算
1:指针与整数的加减运算(在指针的意义已经介绍)
规律(主要看该指针指向类型):ex int * ptr ,ptr指向int型(*代表ptr是指针变
量),所以 ptr - 1就是减了一个int类型的大小
而,int ** ptr ,类比可得 ptr - 1 减了int *的大小
注意:只有指针类型加减才会有不同的宽度,非指针类型加减加一就是加一,减一就是
减 一,不要混淆了
2: 指针与指针之间的加减
也就是地址之间的运算(结果是之间的元素个数不是字节个数)
解引用操作符(*)
通过 指针变量存放的地址,找到指向的空间
用宏替换看待解引用,不要去怕它
注意:*和&可以相互抵消 ex:
{
p = &arr
*p = *&arr = arr
}
有些东西不需要解引用的原来就是地址的变量赋值给指针变量
常见的有 : 函数名,数组名.
注意:初始化指针变量的时候老实一点不要去运算
注意:在定义指针变量时*可不是解引用的意思
野指针:野指针的地址是随机的,是不确定的,是没有明显缺陷的
成因类型
1:局部指针变量未初始化
结果:解引用的时候地址未确定导致非法访问等后果(形成野指针)
穿插知识点:
局部int变量未初始化,默认值未知。
全局int变量(包括有static前缀的)未初始化, 默认值是0。
2:指针越界访问
结果:解引用的时候地址超出导致非法访问等后果(形成野指针)
3:指针指向的地址被销毁:
在自定义函数中经常会发生这种事情因为出来函数后内存就还给操作系统了(对应地
址也就没了)
举例子:宾馆退房
结果:解引用的时候地址不存在导致非法访问等后果(形成野指针)
第三类情况十分易错,记住 ,永远不要返回栈空间地址。这是大忌。
因为返回了就销毁了,
经典错误案例:
规避野指针现象:
1.
如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里,
我们可以给指针赋值NULL NULL是C语言中定义的一个标识符常量,值是0,0也是地址,这个地址是无法使用的,读写该地址会报错。
null的作用还可以提醒其他程序员不要乱动。
二级指针:
牢记:
1.遇到二级指针不要慌用 &和*抵消的思想
2. 一个一级指针的地址,一定是通过对该指针变量&才拿得到
这就形成了二级指针
3.除了遇到,&,二级指针,链表,不要老去想本身的地址
特别的不用二级指针的地方(结构体)
head和tail都是结构体里面的指针,对于结构体操作仅通过”->“就改
变head和tail。不用传二级指针来.