前言:
接下来我们进入C语言里的重头戏---指针。指针是一个很好用的东西,学好指针,无异于打下半片江山。
一.指针基础
指针实际上是用来指向内存空间的一个变量。可能读者会觉得博主说得轻描淡写,我们先抛开先前对指针的恐惧,一步一步来讲,先从内存的基础讲起。
1.1内存单元
内存是存取数据的一块大空间,我们知道,无论是什么事物,不好好利用都会有挥霍完的一天,相应的,要想高利用率的使用好内存空间,计算机前人们在设计的时候,就把内存空间划为一个一个小小的内存单元。
那又如何区分这些长的一样的内存单元呢?在生活中,一栋栋商品房,房型差不多,如何让住户知道自己买的房间在哪里咧,假设有亲戚朋友要来我家,如何让他们知道我住哪里呢?我想,给个编号,给个地址不就好了~,现实中如此,计算机也如此,使用一个个编号给内存单元定义地址。
这个编号是使用地址线(电线)的通电,不通电这两种状态转换成数字信号1,0给内存单元编号,这个编号也就是它们的地址啦。
补充:32位电脑有32根地址线,每一根地址线可以产生0或1的数字信号,总共有2的32次方种组合,也就是可以管理2的32次方个内存单元。64位电脑就可以管理2的64次方个内存单元。
1.2内存单元和指针的大小
那么一个内存单元多大合适呢?在以前我们常说4G、8G内存的电脑。我们姑且来算一下吧,假如一个内存单元只能存储一个bit位,那么32位机器内存大小为2的32次方个bit位:
二进制第33位的1代表2的32次方,我们现在转换成Gb单位需要除以8(Byte)、除以1024(Kb)、除以1024(Mb)、除以1024(Gb)。
由于程序员的除法取商,再除1024就是0了。所以现在是转换到Mb的单位,512Mb就是0.5G,这未免也太小了吧,听过最小的内存也是4G~,那一个内存单元从一个bit位变成一个字节呢?0.5G乘以8变成4G,可以接受~
总结:计算机中一个内存单元是一个字节的大小。
指针是存放内存单元地址的,一个地址的产生前面也说过。如果是32位平台,就用32根地址线生成32个数字信号来编号,那一个地址就是32个bit位,所以指针大小就是4个字节;如果是64位平台,指针大小为8个字节,这是固定的,不会根据数据类型改变指针大小。
总结:指针大小如果在32位平台下是固定4个字节,在64位平台下是固定8个字节。
二.指针变量
如何创建指针变量呢?请看值一段代码:
#include <stdio.h> int main() { int a = 0; int* pa = &a; *pa = 10; printf("%d\n", a); return 0; }
2.1指针类型
和创建普通变量是一样的,指针类型+变量名创建整型指针变量pa。&取地址操作符取出整型变量a的地址放到指针变量pa里面,*解引用pa的意思是找到pa存放的地址对应的内存单元,也就是找到了a,*pa相当于a。
char*、short*、int*、float*、double*的大小分别是多少?都是4个字节的空间大小(32位),那char*类型的指针变量也可以存放整型变量的地址是毋庸置疑的,但这样做对吗?我们看代码:
将a的地址放到char*的指针里面是能放进去的,只是编译器会有一个警告,报的是类型不兼容:
这就是我们这里要讲的指针类型的意义:
指针变量的类型决定了指针解引用时改变多少个字节
指针变量的类型决定了指针加减运算时跳过多少个内存单元
我们使用整型指针可以把-1完全变成0,而使用字符指针却改不成,这是为什么呢?请看:
*pc只改了一个字节,(内存中用十六进制表示,两个十六进制位等于一个字节,16是2的四次方),所以a的补码为0xffffff00;打印的时候转换成原码~
以上解释就是指针类型决定指针访问权限。还有一个指针决定指针加减运算跳过多少个内存单元的问题,博主简单说一下。
一个指向整型的指针+1,指针变量里的地址会指向哪一个内存单元呢?我们看代码:
整型a的起始地址是c4,本来a占有的内存单元有c4、c5、c6、c7这四个内存单元,一个内存单元一个字节,整型变量是四个字节大小嘛。然后使用它的首地址代表a的地址,整型值10就放在这四个内存单元里。p存放的值是a的地址,所以&a和p是一样的。
打印p+1不是等于c5,而是c8,为什么呢?这里我们就得了解指针类型决定指针跳过多少个内存单元。可以这样理解,整型指针加1的意思是:指向下一个整型(当然下一个不一定是整型),只是这样说而已。
2.2野指针
野指针就像野孩子一样,没有人管,这是非常危险的。野指针的常见情况如下:
没有初始化的局部指针变量。
指针指向的变量销毁掉了。
数组越界访问。
局部变量没有初始化是随机值,一个局部指针变量如果没有初始化,那它也是一个随机值;指针变量是存放地址的变量,随机值存放在指针里面会被当成地址看待。如果此时不小心对指针进行了解引用操作,就会对不属于我们的内存单元里的内容进行修改,造成破坏,导致程序挂掉。
指针指向的空间释放掉了,指针就变成了野指针。请看代码:
a是test函数里的局部变量,在test函数里a存在,然后返回a的地址,a出了代码块,生命周期结束,被释放掉了,可是*p还是接收到a变量的地址,但a已经不属于我们了,此时p就是野指针。
数组越界访问变成野指针在后面讨论指针和数组的关系时讲~
避免野指针
在创建指针变量的时候,如果不知道指向谁,初始化为NULL(空指针) |
指针使用完后,赋值成空指针 |
在使用指针之前,用if测试指针现在放的是不是NULL,因为空指针不能解引用 |