指针的介绍
指针变量
指针隐含两种东西:一个是指针变量,一个是指针常量。但是大多数情况下,指针都是指代的指针变量。
指针变量和普通变量相同,都是用于存储数据的,只是指针变量存放的数据很特殊,是内存地址。一般情况下,如果不考虑指针强制转换的话,我们要求某个类型的地址必须放到对应的类型的指针变量中。
int a = 10;
int *p = &a;
以上两句话可以看出指针变量p和普通变量之间没有本质区别,都是变量空间放了一个数值,只是p中间放置的有些区别,是普通变量a的地址值,它指向了空间a。这是我们可以简单的进行说明:指针p指向了空间a。
变量空间的首字节地址,作为整个空间的地址
内存中每一个字节都有一个地址,如果内核有32根地址线,地址以二进制表示,其最大的可寻址范围是:
0000 0000 0000 0000 0000 0000 0000 0000 - 1111 1111 1111 1111 1111 1111 1111 1111
在int a中,我们说a的空间是有4个字节,每个字节都有自己的地址,但是只有首字节的地址才能作为整个变量的地址,所以&a代表的就是第一个字节的地址。拿到空间首地址后,int类型又明确了空间的大小是4个字节,所以从首地址字节顺延3个字节的空间,一共四个字节作为整个变量的空间。
指针变量的类型作用
对于指针变量来说,其类型是由普通类型+星号构成。星号的个数表明了指针变量的级数,指针变量用来存储地址,有如下对应关系:
1、某类型一级指针变量 = 该类型一级地址
2、某类型二级指针变量 = &(该类型以及地址)
3、n+1级指针变量 = &(n级指针变量)
需要注意的是计数超过三的时候,会降低空间的访问速度,所以过高级的指针变量是没有太大意义。
指针使用三部曲
定义,关联、引用
理解指针符号
星号 * 的理解
星号*的个数只代表等级,需要注意的是在这种表达的时候:
int* p;
int *p;
这两种表达是相同的
在* 表达的含义是引用解时,*p所代表的是p所指向的空间,必须强调的是 *p是一个整体,不能分开表达。
取地址符&的理解
int a ;
int *p = &a;
这里的&a是一个不能分割的整体,表达的是a的地址值。
指针变量初始化和指针变量赋值之间的区别
指针变量的初始化
int a = 10;
*p = &a;
这里是进行指针变量的初始化操作
指针变量的赋值
int a =10;
int *p = NULL;//这里是对指针进行初始化,防止出现野指针的问题
p = &a;//这里的p代表着p这个存储空间,这时候是将a的地址值放入到p中
左值和右值
int a = 10;
等号左边的叫做左值,等号右边的叫做右值。
左值:在C语言中左值代表的都是变量空间,对左值执行的操作都是写空间操作。
右值:在C语言中右值有两种形态,一种是直接写一个数值,两一种情况是右值也可能是一个变量。
野指针与段错误的问题
什么是野指针
野指针就是值指针指向一个不确定的地址空间,或者虽然指向一个确定的地址空间,但是引用空间的结果却是不可预知的
举例:
int main(void)
{
int *p ;
*p =10;
return 0;
}
这个例子中,p是自动局部变量,由于p没有被初始化,也没有后续赋值,那么p中存放的是一个随机值,所以p指向的内存空间是不确定的。访问一个不确定的地址空间,结果显然是不可预知的。
int main(void)
{
int *p = 0x13542354 ;
*p =10;
return 0;
}
这里的p虽然指向了一个确定地址的空间,空间中存储的是0x13542354,但是空间是否存在,其读写权限是否满足要求都是未知的,所以说这个指针是野指针。
野指针可能引发的结果
引发段错误
未产生任何结果
引发程序连环式错误
野指针产生的原因
1、在使用指针前忘记将指针变量初始化或者赋值为一个有效的空间地址,导致指向的不确定。
2、在程序中指针试图指向不清楚读写权限的区域。
3、在访问空间时,内存越界导致野指针。
int buf[14] = {0};
*(buf+4) = 10;
这个数组中只有0.1.2.3这几个成员,但是例子中试图访问超出数组范围的空间。
如何避免野指针
1、在定义指针的时候将其赋值为NULL
2、在使用指针变量前,一定要对指针变量初始化或者赋值,让它指向一个有效且确定的值。
3、检查指针的有效性在使用指针前做指针为空的判断
int *p = NULL;
if(NULL != p)
{
*p = 100;
}
else printf("p == NULL\n")
4、当指针变量不再使用的时候,就将其赋值为NULL
const关键字与指针
const表示不变的意思,用于修饰变量,希望将变量变为常量
const 修饰指针的三种形式
- int const *p等价于const int *p;
这种修饰代表的是p所指向的空间是“常量”,不能被修改,但是p本身是可以进行修改的。 - int *const p
这种刚刚好和上面的情况相反,这种代表p这个空间中存储的地址值是不能改变的,但是p所指的空间的内容可以进行改变。 - int const * const p
这种p的指向不能进行改变,而p所指向的空间的内容也不能进行修改。
为什么要用const
const更多的使用在指针变量的形参的修饰。