什么是空指针

C++语言定义中说,每一种指针类型都有一个特殊值----"空指针"。

空指针在概念上不同于未初始化的指针。空指针可以确保不指向任何对象或函数;而未初始化的指针则可能指向任何地方。

空指针不是野指针。每种指针类型都有一个空指针,而不同类型的空指针内部表示可能不尽相同。尽管程序员不必知道内部值,但编译器必须时刻明确需要哪种类型的空指针,以便在需要时加以区分。

1)怎样在程序里获得一个空指针。

根据语言定义,在指针上下文中的常数0,会在编译时转换为空指针。也就是说,在初始化、赋值或者比较的时候,如果一边是指针类型的值或表达式,编译器可以确定另一边的常数0为空指针并生成正确的空指针值。如下所示:

char *p=0;
if(p!=0)

然而,传入函数的参数不一定当做指针环境,因为编译器可能不能识别未加修饰的0表示“指针”。

在函数调用的上下文中,生成空指针需要明确的类型转换,强制把0看成指针。例如,UNIX系统可以调用execl接受变长的以空指针结束的字符指针参数,它应该采取如下的正确调用:

execl("/bin/sh","sh","-c","date",(char* )0);

如果省略最后一个参数的(char* )转换,则编译器无法知道这是一个空指针,而把它当做0。如果在作用域内有函数原型,则参数传递变为“赋值上下文”,从而可以省略类型转换;这是因为,函数原型会告知编译器这里需要指针,使之把未加修饰的0正确转换为适当的指针。

最好是在函数调用时,对所有的空指针进行类型转换。

2)使用“if(p)” 检查空指针是否可靠

如果空指针的内部表达不是0将会怎样?当C语言在表达式中要求布尔值时,如果表达式等于0则认为该值为假,否则为真。换言之,只要写出

if(expr)

无论expr是任何表达式,编译器本质上都会把它作如下处理:

if(expr != 0)

如果用指针p 代替expr,则if(p) 等价于 if(p != 0)。

在此比较上下文中,编译器可以看出 0实际上是一个空指针常数,并使用正确的空指针值。这里没有任何欺骗,编译器就是这样工作的,并为二者生成完全一样的代码。空指针的内部表达无关紧要。

所以,类似于if(p) 这样的“缩写”尽管完全合法,但被一些人认为是不好的风格。

3)NULL是什么,它是怎样定义的

作为一种风格,很多人不愿意在程序里看到到处出现未加修饰的 0,因此编译器在stdio.h 头文件中定义了预处理宏 NULL为空指针常数。

/* Define NULL pointer value */
#ifndef NULL
#ifdef __cpluscplus
#define NULL 0
#else
#define NULL ((void *) 0)
#endif
#endif

通过定义可以看出,NULL和0 其实没有太大的差别。编译时预处理器会把所有的NULL 都还原为 0,而编译还是按照上下文的描述出来指针上下文的 0。特别是在函数调用里,NULL之前的类型转换还是需要的。

【延伸阅读】

在使用非全零为空指针内部表达的机器上,NULL是如何定义的?

(3.1)跟其他机器一样:定义为0 (或某种形式的 0)。

(3.2)当程序员请求一个空指针时,无论写"0"还是“NULL”,都由编译器生成适合机器的二进制表达形式。因此,在空指针的内部表达不为 0的机器上定义NULL 为 0 跟其他机器一样合法:编译器在指针上下文看到的未加修饰的 0 都会生成正确的空指针。

4)如果 NULL和 0作为空指针常数是等价的,到底该用哪一个?

许多程序员认为指针上下文都应该使用NULL,以表明该值应该被看做指针。另一些人认为用一个宏定义 0,只会把事情搞的更复杂,他们倾向于使用未加修饰的 0 。

C程序员应该明白,在指针上下文中 NULL 和 0完全等价,而未加修饰的 0也可以完全接受。任何使用 NULL的地方都应该看作一种温和的指针提示,然而程序员并不能依靠它来区分指针0 和 整数0。

【最佳实践】虽然 NULL和 0具有相同的功能,但建议使用NULL 替代 0。这种实践有两个好处:

(4.1)你可以认为 NULL的值改变了,比如在使用非零内部空指针的机器上,用NULL会比 0 有更好的兼容性,但事实并非如此。

(4.2)尽管符号常量经常代替数字,以备数字的变化,但这不是NULL 替代 0 的原因。语言本身确保了源码中的 0(用于指针上下文)会生成空指针。NULL只是用作一种格式习惯。

5)NULL可以确保是零,但空指针却不一定零

空指针的内部(或者运行前)表达式可能不完全是零,而且对不用的指针类型可能不一样。真正的值只有编译器的开发者才关心。C++程序的作者永远看不到它们,这一点不用担心,明白就好。

【注意】

(5.1)空指针不一定是0,而NULL肯定是0.

(5.2)赋值为空指针的变量,可确保变量不指向任何对象或函数。合理地使用空指针可以有效地避免内存泄露,提高程序的执行效率。

时间: 2024-10-08 12:57:54

什么是空指针的相关文章

由@NotNull 注解引出的关于Java空指针的控制(转)

Java 小技巧和在java应用避免NullPonintException的最佳方法 在java应用程序中,一个NullPonintException(空指针异常)是最好解决(问题)的方法.同时,空指针也是写健壮的顺畅运行的代码的关键.“预防好过治疗”这句话也同样适用于令人不爽的NullPonintException.通过应用防御性的编码技术和在遵守多个部分之间的约定,你可以再很大程度上避免NullPointException.下面的这些java小技巧可以最小化像!=null这种检查的代码.作为

在Servlet使用getServletContext()获取ServletContext对象出现java.lang.NullPointerException(空指针)异常的解决办法

今天遇到了一个在servlet的service方法中获取ServletContext对象出现java.lang.NullPointerException(空指针)异常,代码如下: 1 //获取ServletContext对象 2 ServletContext servletContext = this.getServletContext(); 这个问题很奇怪,也是第一次遇到,因为以前在servlet的doGet/doPost方法中要获取ServletContext对象时都是这样写的,也没有出现过

ios NSClassFromString 返回空指针

今天新建了一个 iOS 新工程,用到了 NSClassFromString 方法创建类, 无奈总是返回空指针. 花了一下午时间检查代码是否有写错,配置是否有问题,搜索这个问题该怎么解决.无奈都没有什么理想的结论.到了晚上的时候看到一个帖子说 other link flags 里面增加-all_load 属性.我一想,这不靠谱啊. 我以前都没有用过这个属性.我又想到这个工程是新建的,是不是这里面少了什么配置.比较了下以前的工程.增加了-ObjC 这个属性, 再跑一下,成功创建了. 在这里我把这个解

C语言指针2(空指针,野指针)

//最近,有朋友开玩笑问 int *p  *是指针还是p是指针还是*p是指针,当然了,知道的都知道p是指针 //野指针----->>>指没有指向一个地址的指针(指针指向地址请参考上一篇文章) //空指针---->>指向空(null)的指针就是空指针 //指针的其他用法,指针可以指向指针,指针可以进行+ - * /运算 /* 特别注意,各个编译器都不相同,这里有一种错误写法,如: int *p,int a=10,b=20; p=&b; *p = &a;    

SpringJUnit4测试--测试无反应/控制台报空指针的解决---junit的jar冲突!

前言: 前些日子碰到一个诡异的问题--用springJUnit进行测试,运行方法什么反应也没有,控制台 也没有输出,百度也没有答案--只好暂时作罢.今天我只好用上了排除法,建个测试小项目,将只要能测试的几个Spring相关jar拷进去,测试正常,然后开始与原项目进行对比排除jar,看看到底是哪个/哪些jar惹的祸导致jar冲突,结果真是出乎我的意料--竟然是自家兄弟!原来这个项目中也有个junit-4.4的jar,把它删掉就好了.(项目build path添加junt4依赖时会导入相应jar,与

野指针 空指针 通用指针

空指针是一个特殊的指针值,也是唯一一个对任何指针类型都合法的指针值.指针变量具有空指针值,表示它当时处于闲置状态,没有指向有意义的东西.空指针用0表示,C语言保证这个值不会是任何对象的地址.给指针值赋零则使它不再指向任何有意义的东西.为了提高程序的可读性,标准库定义了一个与0等价的符号常量NULL.    程序里可以写 p = 0;     或者 p = NULL; 两种写法都把p置为空指针值.相对而言,前一种写法更容易使读程序的人意识到这里是一个指针赋值.操作NULL也会导致不可预知的错误 我

关于空指针NULL、野指针、通用指针

http://www.cnblogs.com/losesea/archive/2012/11/16/2772590.html 首先说一下什么是指针,只要明白了指针的含义,你就明白null的含义了.假设 有语句 int a=10;那么编译器就在内存中开辟1个整型单元存放变量a,我们假设这个整型单元在内存中的地址是 0x1000:那么内存0x1000单元中存放了数据10,每次我们访问a的时候,实际上都是访问的0x1000单元中的10.现在定义:int *p:                 p=&a

僵尸对象与野指针以及空指针

僵尸对象:占用空间被释放的对象 野指针:指向僵尸对象的指针(给野指针发消息会报错) 空指针:指向nil的指针(给空指针发消息会不报错) 因为给野指针发消息会报错,因此我们要监听僵尸对象,这样就可以在控制台输出错误原因 设置如下图

空指针

指针值为空.它不指向任何的对象或者函数.由系统保证空指针不指向任何实际的对象或者函数. 反过来说,任何对象或者函数的地址都不可能是空指针. X* a = NULL/0/'\0'/ (void *)0 空指针(null pointer)指向了内存的什么地方即空指针的内部实现? 标准并没有对空指针指向内存中的什么地方这一个问题作出规定,也就是说用哪个具体的地址值(0x0 地址还是某一特定地址)表示空指针取决于系统的实现.我们常见的空指针一般指向 0 地址,即空指针的内部用全 0 来表示(zero n

C语言中void *指针与空指针区别

void* 这不叫空指针,这叫无确切类型指针.这个指针指向一块内存,却没有告诉程序该用何种方式来解释这片内存.所以这种类型的指针不能直接进行取内容的操作.必须先转成别的类型的指针才可以把内容解释出来. 还有'\0',这也不是空指针所指的内容. '\0'是表示一个字符串的结尾而已,并不是NULL的意思. 真正的空指针是说,这个指针没有指向一块有意义的内存,比如说:char* k;这里这个k就叫空指针.我们并未让它指向任意地点.又或者char* k = NULL;这里这个k也叫空指针,因为它指向NU