全部博文(175)
分类: LINUX
2012-07-11 10:38:09
C/C++野指针
一、莫名的恐惧感 对于指针确实有种莫名的恐惧感,从刚开始学习的时候就被老师灌输的概念是指针功能很强大,但是用得不够好,会有很大的副作用。什么叫用得够好?初学者谁都不会用,那且不是都不能用了?如果都这样,指针都没人用了,还要指针做什么? 陷入了上述困局的原因在于我们的这种莫名的恐惧感,指针如此之神秘,以至于如我一样大多数的人都望而生畏,无所适从,被迫放弃。 二、野指针 诚如当初老师的忠告一样, 指针是个很强大的工具,可是正因为它太强大,所以要操作它不是件易事。操作不当造成的野指针,甚至会引起系统死机等比较严重的后果。
如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为NULL,如果没有这么做,那么这个指针里的内容是不可预知的,即不知道它
指向内存中的哪个空间(即野指针),它有可能指向的是一个空白的内存区域,可能指向的是已经受保护的区域,甚至可能指向系统的关键内存,如果是那样就糟
了,也许我们后面不小心对指针进行操作就有可能让系统出现紊乱,死机了。所以我们必须设定一个空间让指针指向它,或者把指针设为NULL,这是怎么样的一
个原理呢,如果是建立一个与指针相同类型的空间,实际上是在内存中的空白区域中开辟了这么一个受保护的内存空间,然后用指针来指向它,那么指针里的地址就
是这个受保护空间的地址了,而不是不可预知的啦,然后我们就可以通过指针对这个空间进行相应的操作了;如果我们把指针设为NULL,我们在头文件定义中的
#define NULL 0
可以知道,其实NULL就是表示0,那么我们让指针=NULL,实际上就是让指针=0,如此,指针里的地址(机器数)就被初始化为0了,而内存中地址为0
的内存空间……不用多说也能想象吧,这个地址是特定的,那么也就不是不可预知的在内存中乱指一气的野指针了。 还应该注意的是,free和delete只是把指针所指的
内存给释放掉,但并没有把指针本身干掉。指针p被free以后其地址仍然不变(非NULL),只是该地址对应的内存是垃圾,p成了“野指针”。如果此时不
把p设置为NULL,会让人误以为p是个合法的指针。用free或delete释放了内存之后,就应立即将指针设置为NULL,防止产生“野指针”。内存
被释放了,并不表示指针会消亡或者成了NULL指针。(而且,指针消亡了,也并不表示它所指的内存会被自动释放。) 三 例说野指针 例子1: 首先请诸位看以下一段“危险”的C++代码:
之所以说其危险,是因为这是一段完全合乎语法的代码,编译的时候完美得一点错误也不会有,然而当运行到strcpy一句的时候,问题就会出现,因为在这之
前,str的空间已经被delete掉了,所以strcpy当然不会成功。对于这种类似的情况,在林锐博士的书中有过介绍,称其为“野指针”。 例子2:——指针初始化引出的问题 对指针初始化时,引出的应该注意的问题小结: 错处: p定义时没有初始化,p是指向不定,是一个野指针。 (2)把上面的p初始化为NULL 也错: NULL表示没有任何指向。p++没有任何意义,运行时会造成程序崩溃。这里就应该想到不能对NULL的指针进行直接操作。 (3)现在为p初始化为" ": 还错: p指向的是一个const常量的内容,可以通过*(p++)形式引用该值,但是不能改变它指向const的内容。 (4) 问题: 此时数组是一系列的变量了,也就是p一有指向,二不是指向常量的而是指向变量的。所以按理应该行的。问题出在c太小,造成了数组越界,所以错掉!把c的大小改来不比"hello first!"小就行了。 5)对于的就想到用new来初始化了: 现在就可以了,哈,不过,我认为在new时最好还是把它的大小给指出来,如new char[strlen(p1)+1];如果不指定大小,我想p++会指向一些已用得地址,而这些地址又不能随便改,就会造成诸如野指针样程序崩溃了。 小结:对于前面的问题,不防这样来写: 四 造成野指针的原因 1、指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的默认值是随机的,它会乱指一气。 通常避免野指针的办法是正确的使用指针
(1)先看例子:
p++可能引用得空间为非法的。
编译时不会出错,但运行时会造成程序崩溃。
2、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
3、指针操作超越了变量的作用范围。这种情况让人防不胜防。
五 正确使用指针
1.声明一个pointer的时候注意初始化为null :
int* pInt = NULL;
2.分配完内存以后注意ASSERT:
pInt = new int[num];
ASSERT(pInt != NULL);
3. 删除时候注意用对操作符:
对于new int类型的,用delete
对于new int[]类型的,用delete []
4.删除完毕以后记得给他null地址:
delete [] pInt;
pInt = NULL;
5.记住,谁分配的谁回收,不要再一个函数里面分配local pointer,送到另外一个函数去delete。
6.返回local address是非常危险的,如必须这样做,请写注释到程序里面,免得忘记。