对空指针、野指针的一点理解

空指针

1、什么是空指针常量?
  一个表示0值的整数常量,叫做空指针常量,例如:0、“1-1” 它们都是值为0的整数常量表达式,以及 (void*)0 、void* 、NULL 都是空指针常量,空指针常量可以赋值给任何指针类型,因为它是变体类型(void*),但是我们更倾向于使用 NULL 来表示这个空指针常量。对于其它方式(比如0)来表示空指针常量虽然不会产生任何问题,但在根本意义上并不符合空指针常量的定义,因为空指针常量的存在意义在于强调它并不指向任何的对象。

2、什么是空指针?
  空指针是一个特殊的指针,它不指向任何实际的对象或者函数,反过来说,任何对象或者函数的地址都不可能是空指针。得到一个空指针最直接的方法就是运用预定义的NULL,NULL在多个头文件中均都有定义的。
例如:
  初始化一个空指针:int p = nullptr;(C++11引入)
  或者:int p = NULL;(需要引入头文件cstdlib,NULL在该头文件中其实就是字面常量0)
  校验一个指针是否为一个有效指针:if(p != NULL);
  
3、什么是NULL?
  NULL是一个标准规定的宏定义,用来表示空指针常量。在C语言中,NULL是指向0的 void
类型的指针常量,由 #define NULL ( (void
) 0) 定义;在C++中,NULL被直接定义成整数立即数0,由 #define NULL 0 定义。

4、什么是零指针?
  零值指针是值为0的指针,可以是任何一种类型的指针,可以是通用变体类型 void*,也可以是 char*, int* 等等。
  在C++里面,任何一个概念都以一种语言内存公认的形式表现出来的,例如 std::vector 会提供一个empty()子函数来返回容器是否为空,然而对于一个基本数值类型(或者说只是一个类似整数类型的类型)我们不可能将其抽象成一个类(当然除auto_ptr等智能指针)来提供其详细的状态说明,所以我们需要一个特殊值来做为这种状态的表现。
  C++标准规定,当一个指针类型的数值是0时,认为这个指针是空的。(我们在其它的标准下或许可以使用其它的特殊值来定义我们需要的NULL实现,可以是1,可以是2,是随实现要求而定的,但是在标准C++下面我们需要可以用0来实现NULL指针)。
  
5、空指针指向内存的什么地方?
标准并没有对空指针指向内存中的什么地方这一问题作出规定,即用哪个具体地址值表示空指针取决于系统实现。常见的空指针一般指向0地址,即空指针的内部用全0来表示(zero null pointer,零空指针);也有一些系统用一些特殊的地址值或者特殊的方式表示空指针(nonzero null pointer,非零空指针)。

6、对空指针实现的保护政策
逻辑地址和物理地址
  程序中的所说的指针其实是windows内存段偏移后的地址,但不是实际的物理地址,所以不同的地址中的零值指针指向的不是物理内存的开端的0,而是各分段内存的开端,简单介绍一下windows下的内存分配和管理制度:
  windows下,执行文件在被调用后,系统会分配给它一个额定大小的内存段用于映射这个程序的所有内容(就是磁盘上的内容)并且为这个段进行新的偏移计算,也就是说我们的程序中访问的所有near指针都是在我们“自家”的段里面的,当我们需要访问far指针时,我们其实是跳出了“自家的院子”到了他人的地方,我们需要一个段偏移资质来完成新的偏移(人家家里的偏移)所以我们的指针可能是OE02:0045,就是告诉我们要访问0E02个内存段的0045号偏移,然后windows会自动给我们找到0E02段的开始偏移,然后为我们计算真实的物理地址。所以程序A中的零值指针和程序B中的零值指针指向的地方可能完全不同。  
空指针赋值分区
  这一分区是进程的地址空间中从0x00000000 到 0x0000FFFF 的闭区间(64K ),这 64K 的内存是一块保留内存,不能被程序动态内存分配器分配,也不能访问,更不能使用,保留该分区的目的是为了帮助程序员捕获对空指针的赋值。如果进程中的线程试图读取或者写入位于这一分区内的内存地址,就会引发访问违规。
为什么空指针访问会出现异常?
  归根结底,程序中所使用的数据都是需要从物理设备上获取的,即程序中的数据需要从一个真实的物理地址中读取或者写入,所以一个指针的逻辑地址可以通过计算准确无误的映射到一个正确的物理地址上时,这时数据的访问就是正确的,程序的执行也没有任何问题。如果一个指针为空指针,那么该指针所指向的逻辑地址空间位于空指针赋值分区的区间上,空指针赋值分区上的逻辑地址没有物理存储器与之对应,因而访问时就会产生违规访问的异常。

补充:能否将一个空类型的指针赋值给其他类型的指针?
  可以,但需要在前面加强制转换符,记住不支持将一个其他类型的指针赋值给一个空类型的指针。

野指针

1、野指针的概念
  野指针不是空指针,而是一个指向垃圾内存的指针,程序员不能对野指针的内容赋值,因为这是非常危险的,会导致程序运行时崩溃。

2、野指针的产生几种情况
1、指针变量没有被初始化
  任何指针变量在被刚创建时不会被自动初始化为NULL指针,它的缺省值是随机的。所以指针变量在创建时应当被初始化,要么将它设置为NULL,要么让它指向合法的内存,否则它就是一个野指针。
2、指针被free或者delete之后,没有将其设置为NULL
  free和delete只是把指针所指向的内存给释放掉了,但是并没有把指针本身给清理掉,这时候的指针依然指向原来的位置,但这个位置的内存数据已经被销毁了,此时的这个指针指向的内存是一个垃圾内存。此时如果使用if(p != NULL);会逃过校验。
3、指针操作越界了或者临时变量失效了
  由于C/C++中指针有++操作,因而在执行该操作的时候,容易指针访问越界,访问一个不该访问的内存,结果程序崩溃;另一种情况是指针指向一个临时变量的引用,当该变量被释放时,此时的指针就变成了一个野指针。
例如:
A *p; // A为一个自定义对象
{
A a;
p = &a; // 注意 a 的生命期 ,只在程序块中(花括号里面的两行)
}
p->Func(); // p是“野指针”

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值