zl程序教程

您现在的位置是:首页 >  其他

当前栏目

解析C语言中空指针、空指针常量、NULL&0的详解

ampC语言 详解 解析 null 指针 常量 中空
2023-06-13 09:14:53 时间
什么是空指针常量(nullpointerconstant)?

[6.3.2.3-3]Anintegerconstantexpressionwiththevalue0,orsuchanexpressioncasttotypevoid*,iscalledanullpointerconstant.

这里告诉我们:0、0L、"\0"、3-3、0*17(它们都是“integerconstantexpression”)以及(void*)0(tyc:我觉得(void*)0应该算是一个空指针吧,更恰当一点)等都是空指针常量(注意(char*)0不叫空指针常量,只是一个空指针值)。至于系统选取哪种形式作为空指针常量使用,则是实现相关的。一般的C系统选择(void*)0或者0的居多(也有个别的选择0L);至于C++系统,由于存在严格的类型转化的要求,void*不能象C中那样自由转换为其它指针类型,所以通常选0作为空指针常量(tyc:C++标准推荐),而不选择(void*)0。

什么是空指针(nullpointer)?

[6.3.2.3-3]Ifanullpointerconstantisconvertedtoapointertype,theresultingpointer,calledanullpointer,isguaranteedtocompareunequaltoapointertoanyobjectorfunction.

因此,如果p是一个指针变量,则p=0;、p=0L;、p="\0";、p=3-3;、p=0*17;中的任何一种赋值操作之后(对于C来说还可以是p=(void*)0;),p都成为一个空指针,由系统保证空指针不指向任何实际的对象或者函数。反过来说,任何对象或者函数的地址都不可能是空指针。(tyc:比如这里的(void*)0就是一个空指针。把它理解为nullpointer还是nullpointerconstant会有微秒的不同,当然也不是紧要了)

什么是NULL?

[6.3.2.3-Footnote]ThemacroNULLisdefinedin<stddef.h>(andotherheaders)asanullpointerconstant

即NULL是一个标准规定的宏定义,用来表示空指针常量。因此,除了上面的各种赋值方式之外,还可以用p=NULL;来使p成为一个空指针。(tyc:很多系统中的实现:#defineNULL(void*)0,与这里的“anullpointerconstant”并不是完全一致的)

空指针(nullpointer)指向了内存的什么地方(空指针的内部实现)?

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

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

如何判断一个指针是否是一个空指针?

这可以通过与空指针常量或者其它的空指针的比较来实现(注意与空指针的内部表示无关)。例如,假设p是一个指针变量,q是一个同类型的空指针,要检查p是否是一个空指针,可以采用下列任意形式之一——它们在实现的功能上都是等价的,所不同的只是风格的差别。

指针变量p是空指针的判断:
if(p==0)
if(p=="\0")
if(p==3-3)
if(p==NULL)/*使用NULL必须包含相应的标准库的头文件*/
if(NULL==p)
if(!p)<---------------(这里和下面的if(p)都被专门说过一次,null定义不一定是0.这里如果贸然使用!p会很危险的.所以这种写法不能被提倡)
if(p==q)
...

指针变量p不是空指针的判断:
if(p!=0)
if(p!="\0")
if(p!=3-3)
if(p!=NULL)/*使用NULL必须包含相应的标准库的头文件*/
if(NULL!=p)
if(p)
if(p!=q)
...
可以用memset函数来得到一个空指针吗?

这个问题等同于:如果p是一个指针变量,那么

memset(&p,0,sizeof(p));和p=0;

是等价的吗?

答案是否定的,虽然在大多数系统上是等价的,但是因为有的系统存在着“非零空指针”(nonzeronullpointer),所以这时两者不等价。由于这个原因,要注意当想将指针设置为空指针的时候不应该使用memset,而应该用空指针常量或空指针对指针变量赋值或者初始化的方法。
可以定义自己的NULL的实现吗?兼答"NULL的值可以是1、2、3等值吗?"类似问题

[7.1.3-2]Iftheprogramdeclaresordefinesanidentifierinacontextinwhichitisreserved(otherthanasallowedby7.1.4),ordefinesareservedidentifierasamacroname,thebehaviorisundefined.

NULL是标准库中的一个符合上述条件的reservedidentifier(保留标识符)。所以,如果包含了相应的标准头文件而引入了NULL的话,则再在程序中重新定义NULL为不同的内容是非法的,其行为是未定义的。也就是说,如果是符合标准的程序,其NULL的值只能是0,不可能是除0之外的其它值,比如1、2、3等。

malloc函数在分配内存失败时返回0还是NULL?

malloc函数是标准C规定的库函数。在标准中明确规定了在其内存分配失败时返回的是一个“nullpointer”(空指针):

[7.20.3-1]Ifthespacecannotbeallocated,anullpointerisreturned.

对于空指针值,一般的文档(比如man)中倾向于用NULL表示,而没有直接说成0。但是我们应该清楚:对于指针类型来说,返回NULL和返回0是完全等价的,因为NULL和0都表示“nullpointer”(空指针)。(tyc:一般系统中手册中都返回NULL,那我们就用NULL吧)