空指针常量

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

空指针

空指针不指向任何实际的对象或者函数。反过来说,任何对象或者函数的地址都不可能是空指针。

空指针是一个特殊的指针,因为这个指针不指向任何地方。这意味任何一个有效的指针如果和空指针进行相等的比较运算时,结果都是false。

在程序中,得到一个空指针最直接的方法就是运用预定义的NULL,这个值在多个头文件中都有定义。

如果要初始化一个空指针,我们可以这样,

int*ip = NULL;

int *ip = NULL;

校验一个指针是否为一个有效指针时,我们更倾向于使用这种方式

if(ip != NULL)

if(ip != NULL)

而不是

if(ip)

if(ip)

为什么有人会用if(ip)这种方式校验一个指针非空,而且在C++中不会出现错误呢?而且现在很多人都会这样写。

原因是这样的,

// Define   NULL   pointer   value

#ifndef   NULL

#   ifdef   __cplusplus

#     define   NULL      0

#   else

#     define   NULL      ((void   *)0)

#   endif

#endif //   NULL

// Define NULL pointer value

#ifndef NULL

# ifdef __cplusplus

# define NULL 0

# else

# define NULL ((void *)0)

# endif

#endif // NULL

在现在的C/C++中定义的NULL即为0,而C++中的true为≠0,所以此时的if(ip)和if(ip != NULL)是等效的。

NULL指针

NULL是一个标准规定的宏定义,用来表示空指针常量。在C++里面被直接定义成了整数立即数的0,而在没有__cplusplus定义的前提下,就被定义成一个值是0的 void* 类型的指针常量

零指针

零值指针,是值为0的指针,可以是任何一种类型的指针,可以是通用变体类型 void*,也可以是 char*, int* 等等。

在C++里面,任何一个概念都以一种语言内存公认的形式表现出来,例如std::vector会提供一个empty()子函数来返回容器是否为空,然而对于一个基本数值类型(或者说只是一个类似整数类型的类型)我们不可能将其抽象成一个类(当然除了auto_ptr等智能指针)来提供其详细的状态说明,所以我们需要一个特殊值来做为这种状态的表现。

C++标准规定,当一个指针类型的数值是0时,认为这个指针是空的。(我们在其它的标准下或许可以使用其它的特殊值来定义我们需要的NULL实现,可以是1,可以是2,是随实现要求而定的,但是在标准C++下面我们用0来实现NULL指针)

空指针指向内存的什么地方

标准并没有对空指针指向内存中的什么地方这一问题作出规定,也就是说用哪个具体地址值表示空指针取决于系统实现。我们常见的空指针一般指向0地址,即空指针的内部用全0来表示(zero null pointer,零空指针);也有一些系统用一些特殊的地址值或者特殊的方式表示空指针(nonzero null pointer,非零空指针),具体参见 C FAQ。

在实现编程中不需要了解在我们的系统上空指针到底是一个zero null pointer还是 nonzero null pointer,我们只需要了解一个指针是否是空指针就可以了——编译器会自动实现其中的转换,为我们屏蔽其中的实现细节。注意:不要把空指针的内部实现表示等同于整数0的对象表示——如上所述,有时它们是不同的。

对空指针实现的保护政策

逻辑地址和物理地址

既然我们选择了0作为空的概念。在非法访问空的时候我们需要保护以及报错。因此,编译器和系统提供了很好的政策。

我们程序中的指针其实是windows内存段偏移后的地址,而不是实际的物理地址,所以不同的地址中的零值指针指向的同一个0地址,其实在内存中都不是物理内存的开端的0,而是分段内存的开端,这里我们需要简单介绍一下windows下的内存分配和管理制度:

windows下,执行文件(PE文件)在被调用后,系统会分配给它一个额定大小的内存段用于映射这个程序的所有内容(就是磁盘上的内容)并且为这个段进行新的偏移计算,也就是说我们的程序中访问的所有near指针都是在我们“自家”的段里面的,当我们需要访问far指针的时候,我们其实是跳出了“自家的院子”到了他人的地方,我们需要一个段偏移资质来完成新的偏移(人家家里的偏移)所以我们的指针可能是OE02:0045就是告诉我们要访问0E02个内存段的0045号偏移,然后windows会自动给我们找到0E02段的开始偏移,然后为我们计算真实的物理地址。

所以程序A中的零值指针和程序B中的零值指针指向的地方可能是完全不同的。

空指针赋值分区

这一分区是进程的地址空间中从0x00000000 到 0x0000FFFF 的闭区间(64K 的内存大小),这 64K 的内存是一块保留内存,不能被程序动态内存分配器分配,不能访问,也不能使用,保留该分区的目的是为了帮助程序员捕获对空指针的赋值。如果进程中的线程试图读取或者写入位于这一分区内的内存地址,就会引发访问违规。

为什么空指针访问会出现异常

归根结底,程序中所使用的数据都需要从物理设备上获取,即程序中的数据需要从一个真实的物理地址中读取或者写入。所以当一个指针的逻辑地址可以通过计算能够准确无误的映射到一个正确的物理地址上时,这时候数据的访问就是正确的,程序的执行也没有任何问题。如果一个指针为空指针,那么该指针所指向的逻辑地址空间位于空指针赋值分区的区间上。空指针赋值分区上的逻辑地址没有物理存储器与之对应,因而访问时就会产生违规访问的异常。

野指针

野指针不是空指针,是一个指向垃圾内存的指针。

形成原因

1.指针变量没有被初始化。

任何指针变量被刚创建时不会被自动初始化为NULL指针,它的缺省值是随机的。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如:

char* p = NULL;

char* str = (char*)malloc(1024);

char* p = NULL;

char* str = (char*)malloc(1024);

2.指针被free或者delete之后,没有设置为NULL,让人误以为这是一个合法指针。

free和delete只是把指针所指向的内存给释放掉,但并没有把指针本身给清理掉。这时候的指针依然指向原来的位置,只不过这个位置的内存数据已经被毁尸灭迹,此时的这个指针指向的内存就是一个垃圾内存。但是此时的指针由于并不是一个NULL指针(在没有置为NULL的前提下),在做如下指针校验的时候

if(p != NULL)

if(p != NULL)

会逃过校验,此时的p不是一个NULL指针,也不指向一个合法的内存块,造成会面程序中指针访问的失败。

3.指针操作超越了变量的作用范围。

由于C/C++中指针有++操作,因而在执行该操作的时候,稍有不慎,就容易指针访问越界,访问了一个不该访问的内存,结果程序崩溃

另一种情况是指针指向一个临时变量的引用,当该变量被释放时,此时的指针就变成了一个野指针,如下

c语言野指针和空指针,C++中的空指针和野指针相关推荐

  1. C语言指针实数组输入输出,C语言:回来两个数组中第一个元素的指针,并输出这个值...

    C语言:返回两个数组中第一个元素的指针,并输出这个值 // //  main.c //  Pointer_search // //  Created by ma c on 15/8/2. //  Co ...

  2. android wp指针使用方法,Android中的sp和wp指针

    是怎么一回事? wp其实是弱指针的意思,wp类型不能直接对类型T进行操作,要想对T进行某种操作,必需把wp升级为sp指针,使用promote()来实现升级: wpweakp= new T(); spt ...

  3. c++中的类成员函数指针

    c++中的类成员函数指针 文章目录 c++中的类成员函数指针 发生的事情 正常的函数指针定义 定义类的成员函数指针 std::function 发生的事情 最近,想用一个QMap来创建字符串和一个函数 ...

  4. 理解C语言中的空指针和野指针

    在C语言中,指针是一个非常重要的概念,可以用于操作变量和数据结构.但是,指针也是很容易出错的地方.其中包括两种可能的错误:空指针和野指针. 空指针 空指针指代无效的地址,表示指针不指向内存中的任何一个 ...

  5. c6011取消对null指针的引用_C++中的野指针及其规避方法

    今天在调试程序过程中,用到了一些指针的方法,这里记录一下野指针的概念. 1.概念 野指针,也就是指向不可用内存区域的指针.通常对这种指针进行操作的话,将会使程序发生不可预知的错误. 野指针与空指针(N ...

  6. C语言中的空指针、空指针常量、NULL 0

    C语言中的空指针.空指针常量.NULL & 0  本文转自: http://bbs.chinaunix.net/viewthread.php?tid=544415&extra=& ...

  7. 【C 语言】结构体 ( 结构体中嵌套二级指针 | 为 结构体内的二级指针成员 分配内存 | 释放 结构体内的二级指针成员 内存 )

    文章目录 一.结构体中嵌套二级指针 1.结构体中嵌套二级指针 类型声明 2.为 结构体内的二级指针成员 分配内存 3.释放 结构体内的二级指针成员 内存 二.完整代码示例 一.结构体中嵌套二级指针 1 ...

  8. 【C 语言】结构体 ( 结构体中嵌套一级指针 | 分配内存时先 为结构体分配内存 然后再为指针分配内存 | 释放内存时先释放 指针成员内存 然后再释放结构头内存 )

    文章目录 一.结构体中嵌套一级指针 1.声明 结构体类型 2.为 结构体 变量分配内存 ( 分配内存时先 为结构体分配内存 然后再为指针分配内存 ) 3.释放结构体内存 ( 释放内存时先释放 指针成员 ...

  9. 【示例】C语言中利用数组存放函数指针

    C语言中利用数组存放函数指针,增加函数使用的灵活性.使用时只需提供数组索引,即可调用不同函数. 预备知识: 1.指向函数的指针 一个函数在编译时被分配一个入口地址,这个地址就被称为函数的指针. 例如: ...

最新文章

  1. 夏天过去了, 姥爷推荐几套来自smashingmagzine的超棒秋天主题壁纸
  2. 22.25在计算机中如何储存,浮点数在计算机中存储方式
  3. 部署IPV6有什么好处?
  4. P2577 [ZJOI2005]午餐
  5. 优秀程序员必备素质——快速调试
  6. Nature长文:打破AI黑盒的“持久战”
  7. java linux获取实时cpu_用java取得linux系统cpu、内存的实时信息(参考别人代码)...
  8. TensorFlow 教程 --进阶指南--3.4数据读取
  9. 【学习OpenCV4】滚动条Trackbar的创建与使用详解
  10. 乡村黄昏[原创诗一首]
  11. Unity3D开发:向Unity3D中导入外部模型
  12. java面试题总结-详细分类
  13. jupyter自动补齐插件安装后没有Nbextensions 不显示jupyter lab自动补全插件jupyter lsp的安装与使用
  14. 金蝶系统更换服务器怎么操作系统,换主机金蝶服务器怎么安装
  15. layui图标大全,精心整理
  16. 使用 ssh 连接安装 Anaconda
  17. netty的基本介绍
  18. java godex500_科诚 Godex 打印机驱动下载
  19. hp外带检测服务器硬件,HP Gen10 MicroServer 篇一:#原创新人#惠普 HP Gen10 MicroServer 家用服务器 开箱...
  20. 告别XML,Android新声明式UI框架《Jetpack Compose入门到精通》最全开发指南

热门文章

  1. php class类的用法详细总结
  2. oracle数据库存储过程中NO_DATA_FOUND不起作用解决
  3. Spring Bean init-method 和 destroy-method实例
  4. SqlBulkCopy加了事务真的会变快吗?
  5. C#代码规范 .NET程序员需要提升的修养1
  6. Java与C#事件处理详细对比
  7. soapui模拟桩mockservice---模拟后台服务器
  8. mysql数据导入导出方法总结
  9. 支付宝服务窗的简单开发体会
  10. 1000 驱动_华为海思自研OLED驱动芯片已流片:最高28nm、可完全去美化