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

2017-01-07 19:02:10来源:CSDN作者:dengm155人点击

转载: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;
当编译器遇到语句int *p时,它也会在内存中给指针变量p分配一个内存单元,假设这个单元在内存的编址为0x1003;此时,0x1003中的值是不确定的,(因为我们没有给指针赋值),当编译器遇到了p=&a时,就会在0x1003单元中保存0x1000,请看,这就是说:(指针变量p代表的)内存单元0x1003存放了变量a的内存地址!用通俗的话说就是p指向了变量a。
p=NULL,就是说:内存单元0x1003不存放任何变量的内存地址。

删除一个new了的数组。有必要的话。比如非标准的类( new CMyClass),在Type *p = new Type[N]; delete []p;的最后最好再加一句:   p = NULL

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

我们印象中C语言的指针都有类型,实际上也存在一种例外。这里涉及到通用指针,它可以指向任何类型的变量。通用指针的类型用(void *)表示,因此也称为void 指针。
int n=3, *p;
void *gp;
gp = &n;
p=(int *)gp1;

野指针,也就是指向不可用内存区域的指针。通常对这种指针进行操作的话,将会使程序发生不可预知的错误。 
“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。野指针的成因主要有两种:

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

二、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。别看free和delete的名字恶狠狠的(尤其是delete),它们只是把指针所指的内存给释放掉,但并没有把指针本身干掉。通常会用语句if (p != NULL)进行防错处理。很遗憾,此时if语句起不到防错作用,因为即便p不是NULL指针,它也不指向合法的内存块。例:

char *p = (char *) malloc(100);

strcpy(p, “hello”);

free(p); // p 所指的内存被释放,但是p所指的地址仍然不变

if(p != NULL) // 没有起到防错作用

strcpy(p, “world”); // 出错

另外一个要注意的问题:不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。
指针是个很强大的工具,可是正因为它太强大,所以要操作它不是件易事。操作不当造成的野指针,甚至会引起系统死机等比较严重的后果。  如果程序定义了一个指针,就必须要立即让它指向一个我们设定的空间或者把它设为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、指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的默认值是随机的,它会乱指一气。 2、指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。 3、指针操作超越了变量的作用范围。这种情况让人防不胜防。

======================================================

【转载】空指针赋值分区

为什么通过空指针读写的时候就会出现异常?

  1. 除了NULL表示空指针,是否还有其他的值也是空指针?
  2. 如果还有其他的值,你们这些表示空指针的值都是什么?为什么?

首先解答第一个问题,在windows核心编程第四版的windows的内存结构一章中,表13-1有提到NULL指针分配的分区。其范围是从0x00000000到0x0000FFFF。这段空间是空闲的,对于空闲的空间而言,没有相应的物理存储器与之相对应,所以对这段空间来说,任何读写操作都是会引起异常的。

有了上面的解答后,第二个问题就很容易解答了。NULL的定义出现以下几个地方:

stdio.h文件中

#ifndef NULL 
#ifdef  __cplusplus 
#define NULL    0 
#else 
#define NULL    ((void *)0) 
#endif 
#endif

ios.h文件中

#ifndef NULL 
#define NULL    0 
#endif

windef.h文件中

#ifndef NULL 
#ifdef __cplusplus 
#define NULL    0 
#else 
#define NULL    ((void *)0) 
#endif 
#endif

可见,NULL的值,基本上是用0来表示的,是不是只能用0呢?在windows xp sp2的系统平台下,如果执行下面代码也是会发生异常的:

int * pAddr = (int *)0x0000ffff;

*pAddr = 1;

而下面的代码是不会出问题的:

int * pAddr = (int *)0x00010000;

*pAddr = 1;

为什么呢?在windows xp sp2下发现0x00000000到0x0000FFFF是空闲区间,而0x00010000所处的是进程的私有区间。我想第二个问题应该已经解决了,我想,空指针是程序无论在何时都没有物理存储器与之对应的地址。为了保障“无论何时”这个条件,需要人为划分一个空指针的区域,固有上面NULL指针分区。

在第二个问题的基础上,要解答NULL指针的范围,那就相对来说容易了,对于在32位x86计算机上运行的windows xp sp2来说,就是从0x00000000到0x0000ffff。为什么分配如此大的空间?而在定义NULL的时候,只使用了 0x00000000这么一个值,这不是浪费吗?我想,这是操作系统地址空间的分配粒度相关的,windows xp sp2的分配粒度是64KB,为了达到对齐,空间地址需要从0x00010000开始分配,故空指针的区间范围有那么大。

 =============================================================

【讨论】空指针究竟指向了内存的哪个地方?
转自:领测软件测试网[http://www.ltesting.net] 
原文链接:http://www.ltesting.net/ceshi/ruanjianceshikaifajishu/rjcskfyy/dotnet/2007/0525/6080.html

大家都知道: 
[code:1:4094d314c8]int *p; 
p = NULL;[/code:1:4094d314c8] 
是说明p为一个空指针。NULL在"stdio.h"中被宏定义为0(或其他什么常数〈视编译器而定〉),而这样又并不是说p指向的地址为0,那么各位大侠,这时p究竟指在哪儿呢?不会就这么悬着吧?!

望高手告知其中的细节。不胜感激!!

 kj501 回复于:2005-05-13 11:48:51  
以前有过讨论,搜索论坛看看。好象精华中也有。

 
 gngwzz 回复于:2005-05-13 12:44:25  
空指针指向你进程私有地址的0地址,,它不会被分配出去,,主要的不是null指在哪,而是如果指向null,我们的代码就可以用if(ptr)来判断它是不是有效的指针,不过,如果这个指针不是指向0,也有可能不是个有效的指针,,所以建议程序员在定义指针时把它初始化为0,

 
 hhlcjcj 回复于:2005-05-13 17:18:31  
受教

 
 FH 回复于:2005-05-13 17:25:39  
NULL不一定是0!这句话是俺今天第二次说。 
NULL只是一个概念,叫作空值,其值本身没有任何含义,可以用0代替,也可以用1,...代替,只要这些值不会与系统实际的有效地址冲突即可。 
因此,本人在此再次强调,不要自作聪明地认为NULL就是0,要判断的时候还是老老实实地与NULL做比较,别想当然地用什么!ptr之类的写法,因为在某个特定环境下,NULL可能不是0,而系统函数返回的是NULL不是0,那时,你的函数就会出现莫名其妙的错误。所以,养成良好的习惯是非常重要的。 
忘了是谁第一个用了!ptr这样的写法,这个人该杀!害了多少人啊!

 
 kj501 回复于:2005-05-13 17:29:34  
[quote:a34b12769f="FH"] 
别想当然地用什么!ptr之类的写法,....[/quote:a34b12769f] 
印象中好象林锐写的《高质量c/c++编程指南》上就是这么提倡的。


 
 win_hate 回复于:2005-05-13 23:42:52  
空指针保证不是一个合法地址,这是标准规定的。

 
 FH 回复于:2005-05-14 01:18:46  
[quote:f8f6d3ff5f="kj501"] 
印象中好象林锐写的《高质量c/c++编程指南》上就是这么提倡的。[/quote:f8f6d3ff5f]

那说明他就该杀!他的书是垃圾!审稿的人也是饭桶!

 
 qunying 回复于:2005-05-14 01:50:01  
你的说法并不正确. 

请见翻译: 
[url]http://c-faq-chn.sourceforge.net/ccfaq/node59.html[/url] 
特别是[url]http://c-faq-chn.sourceforge.net/ccfaq/node69.html[/url]

[quote:7730b2a634="FH"]NULL不一定是0!这句话是俺今天第二次说。 
NULL只是一个概念,叫作空值,其值本身没有任何含义,可以用0代替,也可以用1,...代替,只要这些值不会与系统实际的有效地址冲突即可。 
因此,本人在此再次强调,不要自?..........[/quote:7730b2a634]

 
 FH 回复于:2005-05-14 01:55:04  
没觉得楼上引用的文字与俺的见解有什么冲突,相反,说得比俺更过火。比如:“每种指针类型都有一个空指针, 而不同类型的空指针的内部表示可能不尽相同。”再如:“空指针的内部 (或运行期) 表达形式, 这可能并不是全零, 而且对不用的指针类型可能不一样。”

 
 qunying 回复于:2005-05-14 02:01:03  
也许这一段可能更适合 对 if (!ptr) 的讨论[url]http://c-faq-chn.sourceforge.net/ccfaq/node62.html[/url]

 
 qunying 回复于:2005-05-14 02:13:45  
[quote:450a3da0e5="FH"]没觉得楼上引用的文字与俺的见解有什么冲突,相反,说得比俺更过火。比如:“每种指针类型都有一个空指针, 而不同类型的空指针的内部表示可能不尽相同。”再如:“空指针的内部 (或运行期) 表达形式, 这可能并不是全..........[/quote:450a3da0e5] 
我举个例子: 
例如  (假设指针的长度为4个字节, 又假设这个机器上的空指针表达为"0x10000000". 
union { 
char a[4]; 
int *p; 
} u; 
当你用 memset(u.a, 0, 4); 设a为全0时, 并不能假设 p 是空指针 (我们的空指针是0x10000000) . 可是你可以用 if (p == 0) 来判断 p 是否为空指针. 编译器会自动把 0 转换为 0x10000000 与 p 进行比较.

是不是觉得有点晕? 我也是理解了好久才明白.

 
 FH 回复于:2005-05-14 03:40:03  
“memset(u.a, 0, 4); 设a为全0时, 并不能假设 p 是空指针” 
谁说这样就能够让p为空指针了?memset里面说了?概念简直一塌糊涂。

 
 qunying 回复于:2005-05-14 03:49:49  
也许我没讲清楚, 我并不是说这样就可以设 p 为空指针, 而只是为了更好的说明 空指针本身的内部表达和 进行 if (p) 的判断的不同.  在我们虚构的机器上 (if p == 0) 返回的是否, 而不是真.

另外 可以用 u.p = 0 将 p 初始化为空指针, 但 p 的值由编译器转化为了 0x10000000 
我门是不需要知道机器内部是怎样表达空指针的, 这是编译器的工作.

 
 win_hate 回复于:2005-05-14 09:32:55  
[quote:fa3af42415="FH"]

那说明他就该杀!他的书是垃圾!审稿的人也是饭桶![/quote:fa3af42415]

 

上次有个谁来着,说那本书是 <<c/c++ 高质量笑话>>. :D

 
 win_hate 回复于:2005-05-14 09:44:53  
我对 if (p) 的看法:

1、(char *)0, (void *)0... 均为所谓的``零指针''

2、在指针上下文 0 会被提升为相应的 ``零指针'',其部表示取决于机器

3、if (p == 0) 是合法的

(p==0) 为指针类型与常数 0 比较,常数 0必须被提升,提升为相应类型的“零指针”(type *) 0

4、if(p) 也是合法的: 
因为 if(p) 会被编译器处理为 if (p == 0),然后归结到 3

至于风格的问题,我就不讨论了。

 
 gvim 回复于:2005-05-14 11:32:08  
NULL是编译器处理的,靠上下文判断,概念就是“空”。编译器做的不符合标准的,程序错误的读取或修改(void*)0指向的地址,可能不会造成错误(也可能会,主要看机器结构对绝对0地址的处理方式)。而好的编译器,几乎都有这样的检查,来避免对0地址的读写。(如果你非要把NULL当成 0 地址的话)

 
 kernelxu 回复于:2005-05-14 20:55:16  
[quote:250e81197d="win_hate"]我对 if (p) 的看法:

1、(char *)0, (void *)0... 均为所谓的``空指针常数''

2、在指针上下文 0 会被提升为相应的 ``空指针常数'',其部表示取决于机器

3、if (p == 0) 是合法的

(p==0) 为指针类型与常..........[/quote:250e81197d]

同意! 
在stdio.h头文件中,NULL被宏定义为0,所以程序在编译时将NULL替换成0, 
1、若NULL本身不是被宏定义成0,那么在此时使用NULL就不是表示空指针了,对吗? 
2、若在程序中使用了null来表示空指针,因为只有NULL被宏定义为0,所以null不能表示空指针,对吗? 
3、若1、2都对的话,是不是可以说标准C语言就是以p==0来判断p为空指针,用p = 0 使p空指针? 
4、在指针上下文 0 会被提升为相应的 ``空指针常数'',其内部表示取决于机器

 
 qunying 回复于:2005-05-15 03:56:19  
[quote:a41422e576="kernelxu"]

同意! 
在stdio.h头文件中,NULL被宏定义为0,所以程序在编译时将NULL替换成0, 
在stdio.h头文件中,NULL被宏定义为0,所以程序在编译时将NULL替换成0, 
1、若NULL本身不是被宏定义成0,那么在此时使用NULL就不是表示空指针了,对吗? 
2、若在程序中使用了null来表示空指针,因为只有NULL被宏定义为0,所以null不能表示空指针,对吗? 
3、若1、2都对的话,是不是可以说标准C语言就是以p==0来判断p为空指针,用p = 0 使p空指针? 
4、在指针上下文 0 会被提升为相应的 ``空指针常数'',其内部表示取决于机器 
[/quote:a41422e576]

1. 标准中 NULL 被定义为 0 或 (void *)0,判断也是用 if (p == 0) 进行的。如果你用的系统 NULL 不是定义为0 或 (void *)0, 那就不是标准C,我怀疑是否有这样的C. 除非你自己重定义了 NULL, 那此NULL就不是彼NULL了,那可是存心找自己麻烦。

2. null 只是英文里用来表示空的意思,在C语言中没有意义。除非自己定义了名为“null"的变量或宏,能不能表示空指针就看具体定义了,不过一般人不会这么无聊,不用标准NULL,而用自定义的null。

3. 标准C语言就是以p==0来判断p为空指针,用p = 0 使p空指针. 
4. 对

 
 kernelxu 回复于:2005-05-15 21:39:09  
理解! 
谢谢各位指点! :em02:  :em02:

 
 我不懂C++ 回复于:2005-05-16 19:38:03  
[quote:2276ec4906="FH"]NULL不一定是0!这句话是俺今天第二次说。 
NULL只是一个概念,叫作空值,其值本身没有任何含义,可以用0代替,也可以用1,...代替,只要这些值不会与系统实际的有效地址冲突即可。 
因此,本人在此再次强调,不要自?.........[/quote:2276ec4906] 
我完全同意FH关于“NULL不一定是0”的观点。NULL本身就是一个宏。 
#define NULL "FH" 
#define NULL "abc" 
#define NULL printf 
... 
这些都是合法的C/C++预处理语句。 
正因为这点,所以,在我们比较指针是否为空的时候,一个更好的方法是把它和0比较。譬如说: 
if ( str == 0 ) 
    abort();//传进来的字符串是空的,叫人怎么活? 
这是因为如果你写 
if ( str == NULL ) 
万一有某个好事之徒像FH说的那样把NULL定义成1、2、3、...了,那怎么办?(虽然这种人该杀) 
因此,结论就是,推荐使用0作为空指针初始化以及判断的标准。

愿上帝与你同在,阿门!

 
 yuxh 回复于:2005-05-16 19:40:36  
宏定义是个约定,如果谁都可以随便推翻这些约定的话,那还有什么语言?

 
 keenor 回复于:2005-05-16 20:25:13  
NULL指针的值一定是0,这点可参照C语言标准。以下来自C99(WG14/N843 1998): 
[quote:38ae1b66c1] 
       [#3] An integer constant expression with  the  value  0,  or 
       such  an  expression  cast  to type void *, is called a null 
       pointer constant.46)  If a null pointer constant is assigned 
       to or compared for equality to a pointer,  the  constant  is 
       converted to a pointer of that type.  Such a pointer, called 
       a null pointer,  is  guaranteed  to  compare  unequal  to  a 
       pointer to any object or function. 
[/quote:38ae1b66c1] 
..... 
[quote:38ae1b66c1] 
       46)The macro NULL is defined in <stddef.h> as a null pointer 
          constant; see 7.17.

[/quote:38ae1b66c1] 
第一段说得很清楚,值一定是0,而类型可以是void *,也可以是int。 
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n843.htm

 
 gvim 回复于:2005-05-16 21:56:01  
no,no,no 
NULL只是一个表示“空”“无”的概念,可是计算机不能用一个"实物"来表示“空”“无”等概念,所以只有借助辅助的手段。最常用的,而且数学中表示这个概念的,也就是0了。可是0在计算机里面一些场合却又表示一个实际存在的东西,也就是说要一个实际存在的实体表示一个概念,这个似乎有些矛盾。怎么办?那么只能由编译器来解决,在上下文环境中来判断0应该是什么东西。比如在指针环境里,就把0当成“空”这样一个概念,在其他比如数值环境里面,就把0当成实数0。 
而如果错误是用NULL,(在C语言里面也就是实数0,此时0有两种含义),当然会造成错误。

至于NULL是不是0,答案是不一定。因为NULL表示概念,0却可以表示实数0。所以在数据库中,NULL就不是用0表示(这句话是我上学的时候从老师那里听来的)

notice,NULL is just a conception not a real number!

 
 qunying 回复于:2005-05-17 02:36:17  
我们讨论的是C语言. 在标准C里NULL就是被定义为0或(void*)0的. 不要混淆了概念空和C中的NULL宏定义. 我们这边讨论的NULL指的是宏定义. 而机器的实际空指针值,一般是不需要知道的.

数据库中的定义是另一回事.

如果一个"程序员"自己定义了另一个非零的NULL , 那他是在违反标准,给自己和他人找麻烦.

 
 aero 回复于:2005-05-17 08:44:58  
[quote:f7476044ef="FH"]

那说明他就该杀!他的书是垃圾!审稿的人也是饭桶![/quote:f7476044ef]

^_^,9494,可就是还有很多人推荐,唉,看起来像那么回事而已。

 
 aero 回复于:2005-05-17 08:56:28  
^_^,大家说的都是一回事啊。

FH可能做的是嵌入式部分,经常要自己实现C标准,所以,必须要了解到NULL是“空”的概念,而不一定是0地址。

而一般情况下,对0的上下文发翻译(是否翻译成0地址),可以由编译器去做。所以,上了一个层次,就可以简单的认为NULL的值就是0了,这也就是标准中说的这个意思。

风格建议上,还是尽量多使用if(p == NULL)这样的写法,毕竟,这更加靠近本质。

 
 lchhcllch 回复于:2005-05-17 11:30:49  
说到空,就想到了空即是色,色即是空了.题外了. 
对于返回,还是以NULL为主了,对于标准函数的返回指针也明确是返回NULL(意思),不必强行在是不是等于零上下功夫. 
毕竟不要跳过宏定义去划等号.

 
 wolf0403 回复于:2005-05-17 18:22:36  
C 中 NULL 表示为 (void*)0,并且可以用 if ( p ) 和 if ( !p ) 来判断一个指针是否为空,好像是在 TCPL 中规定的通用方法。规定 NULL 为别的什么东西,就像规定 strcmp 为复制字符串一样可笑。

扯远一点,C++ 98 标准中规定空指针就是 0,甚至不用 NULL 这个宏或者 (void*) 0 这种类型修饰符。

 
 我不懂C++ 回复于:2005-05-17 20:29:10  
[quote:1a257c0a21="keenor"] 
第一段说得很清楚,值一定是0,而类型可以是void *,也可以是int。


http://www.open-std.org/jtc1/sc22/wg14/www/docs/n843.htm[/quote:1a257c0a21] 
这个,标准有说“NULL指针的值一定是0”吗?

 
 wolf0403 回复于:2005-05-17 20:39:33  
因为 NULL 必须是通用类型的,所以 C 规定是 (void*)0 。C++ 中直接以 0 作为特殊值处理。

 
 Imt1024 回复于:2005-05-17 23:27:54  
我估计NULL应该是这样实现的, 
首先应该保证 NULL所指向的内存,不在用户空间,而是在内核, 
如果我们对空指针操作,就会引发一个中断,因为user没有权限 
在内核空间操作,系统可能会中断该用户程序,报告segment fault 
之类错误.  实现中可能是系统将整个虚地址空间分成用户和系统两部分, 
NULL所对应的空间应该映射在内核空间,不知道理解对不?

 
 wolf0403 回复于:2005-05-18 00:41:21  
虚拟内存是有权限控制的。0x0 这个位置是规定了不可读写,因此试图读写的时候必然引发 Access Volitation

 
 qunying 回复于:2005-05-18 00:41:41  
感觉我们的讨论把 空指针(null pointer) 和 NULL 宏定义混在一起了. 有时把NULL当作概念用,有时把NULL当作宏定义用.

NULL作为宏定义肯定是为零的. 这是标准C规定的,不然有很多代码都不能工作了. 即使在嵌入式系统中, 如果真的需要知道并了解空指针的值, 那也应该另外定义一个宏,而不是重新定义标准. 但大多数情况我们根本不许要知道空指针的值是什么.

 
 Solaris12 回复于:2005-05-18 15:17:44  
[quote:4e168948ef="wolf0403"]C 中 NULL 表示为 (void*)0,并且可以用 if ( p ) 和 if ( !p ) 来判断一个指针是否为空,好像是在 TCPL 中规定的通用方法。规定 NULL 为别的什么东西,就像规定 strcmp 为复制字符串一样可笑。

扯远一点,C++ 98..........[/quote:4e168948ef]

忍不住说上一句,标准和实现往往是两回事, 
如果写代码的时候把NULL和0混用, 
恐怕会吃亏的。 
尤其是做kernel和嵌入式系统的程序员。

 
 win_hate 回复于:2005-05-18 15:33:52  
[quote:10d51b3e48="Solaris12"]

忍不住说上一句,标准和实现往往是两回事, 
如果写代码的时候把NULL和0混用, 
恐怕会吃亏的。 
尤其是做kernel和嵌入式系统的程序员。[/quote:10d51b3e48]

哪我该怎么办?用 0 还是用 NULL。

如果一个实现修改了0 的含义(注意这时它不能称为一个c 编译系统),if (p) 这种写法可能会完蛋,但如果另一个实现修改了  NULL 的含义, if(p == NULL) 也会完蛋的。


我觉得只要按标准写就行了,出了问题不是还有手册吗? 改就是了。

 
 我不懂C++ 回复于:2005-05-18 19:20:36  
[quote:d2ad3447fe="qunying"]NULL作为宏定义肯定是为零的. 这是标准C规定的[/quote:d2ad3447fe]
应该没有这样的规定吧?

 
 flw 回复于:2005-05-18 21:27:52  
win_hate qunying xiaoming FH 的看法我都赞同.

FH 对 qunying 有一次误会。

to FH: 
唯一不甚明了的一点就是 
if ( !ptr ) 
这种写法应该是正确的吧?

我发现大家争论的原因所在了:都是语言表达不清惹的祸 
现在拨号,就不说了。 
明天写个总结。

 
 gvim 回复于:2005-05-18 23:14:19  
哎,把原理说出来,反而说我混淆是非。。。 
计算机说白了就是数学。NULL只不过是数学概念的计算机表示(represent) 
有否想过何为NULL?它表示什么?为何要定义为0而不是-1,-2。。? 
java的NULL是数字0吗?SQL的NULL是数字0吗?其他类似语言的概念表示是怎样? 
怎么都只看ansi C的表象认为NULL就是0呢? 
只有了解了NULL的本质,才不会问出“空指针究竟指向了内存的哪个地方  
”这样的问题。 
借用对象概念:NULL就是一个数学类,#define NULL 0 只是一个C++语言的NULL的实例化(instance),#define NULL (vois*)0 又是C语言的实例化,SQL的NULL实例化为另外一个。。等等,ni不能说NULL就是0,也不能说0就是NULL。


概念已说明,多说无益,各位继续。。

 
 ChinaDream 回复于:2005-05-18 23:26:24  
[quote:d29bcf7a57="kernelxu"]是说明p为一个空指针。NULL在"stdio.h"中被宏定义为0(或其他什么常数〈视编译器而定〉),而这样又并不是说p指向的地址为0,那么各位大侠,这时p究竟指在哪儿呢?不会就这么悬着吧?!

望高手告知其中的细节。不..........[/quote:d29bcf7a57]

在MEM中有个地址转换表!空指针指向一个内核保留的只读地址!由MEM(内存管理)完成映射

 
 qunying 回复于:2005-05-19 01:48:34  
空指针究竟指向了内存的哪个地方?这个问题本身没有意义. 在概念上空指针代表一个不指向任何地方的指针. 实现上, 空指针在系统中有个特殊值, 但一般上我们不需要知道这个特殊值. 我们只要记住在C里 if(ptr) 和 if(ptr != NULL) , 
if (ptr == 0) 和 if (ptr == NULL) 的判断完全等价, 这两种形式都是正确的, 唯一区别在于风格. 

即使在嵌入式系统中, 如果你不是直接实用汇编语言, 你也不需要知道空指针的值, 只要编译器还是支持标准C,那 if(ptr) 和 if(ptr != NULL) ,


if (ptr == 0) 和 if (ptr == NULL) 的判断还是一样的. 如果某一接口设备用了特殊值(而编译器不知道)代表空, 那也是应该另外定义一个代表形式, 而不是改写NULL的定义. 这里NULL只表示C中的宏定义.

 
 思一克 回复于:2005-05-19 09:16:55  
如果 “if(ptr) 和 if(ptr != NULL) ,”等价, 
那么NULL就一定是(void*)0

 
 win_hate 回复于:2005-05-19 09:35:11  
我又把标准看了一下,发现很有趣的描述。


1、0, (void *0) 是零指针常数,用于指针比较时,不等于任何有意义的指针(指向合法位置的指针)。

2、NULL 被规定为: 实现指定的零指针常数,在 stddef.h 中定义。(没有说是否就一定为0。)

从这两点我们至少可以知道,按标准

if (!p), if (p==NULL) 都是合法的,如果遇到了不标准的实现,自认倒霉好了。


注意一点:NULL 是``实现定义的零指针常数''。 
隐含如下的意思:NULL 不必为0,除了指定零指针常数外,具体实现还可以定义别的零指针常数。一个标准的编译器必须同时能支持这两种零指针常数,尽管它们可能是一样的。


 
 kernelxu 回复于:2005-05-19 09:39:37  
[quote:1496cb9185="ChinaDream"]

在MEM中有个地址转换表!空指针指向一个内核保留的只读地址!由MEM(内存管理)完成映射[/quote:1496cb9185]

说到点子上,谢谢!

 
 kav 回复于:2005-05-19 10:00:57  
学习

 
 我不懂C++ 回复于:2005-05-19 11:36:38  
to yuxh: 
我很同意宏定义是一个约定,但是我想说的是,违反了宏定义,和语言本身并没有关系。宏定义虽然和语言有千丝万缕的关系,但是严格的说,还是在语言之外的。

to keenor以及后面的某些人: 
我想指出你的一个小小的逻辑错误。你这两段话,只能说明,在stddef.h里面定义的NULL必须是那个null pointer constant。但是标准从来没有说过,如果我在另一个不相关的头文件里面定义一个NULL,并且定义为其它东西,就会不符合标准。虽然我承认那样做的可能性很小,但是逻辑上,我们不能用你的话得出这个推断。 
这就好像如果在一本法典里面规定: 
1.暴露行为:=裸体|方便 
2.在公共场所有暴露行为,就是有伤风化罪 
从这两条,我们不能判定出,在家里洗澡也有伤风化。

to qunying: 
我承认一个人把NULL定义为其它东西,是给自己和别人找麻烦,但是我不同意这是违反标准的。理由同上。

有人可能会说,为什么不用宏呢?直接使用常量不是一个不好的习惯吗?问题在于,我们为什么用宏呢?我觉得宏有三个作用:助记/抽象,简化输入。NULL和0相比,简化输入是肯定不可能的。至于助记抽象的话,这就要看了。我们都看到过这样的宏: 
#define PAGE_SIZE (32*1024) 
有谁看到过这样的宏? 
#define ONE_HUNDRED_AND_TEN (110) 
前面的一个宏很好,它赋予数字更多的意义。后面的那个宏很烂,因为没有赋予什么意义。而现在ANSI的意思就是,大家就都把0认为是null吧,别再助记了。也就是说 
#define NULL (0) 
某种意义上说,和前面第二个宏差不多。

有人说,既然一般没毛病的,都会把NULL定义为0,那么我们也就这样用好了。但是这的确会偶然产生问题。譬如说: 
https://lists.openafs.org/pipermail/openafs-devel/2002-March/007721.html 
http://lists.gnu.org/archive/html/uisp-dev/2004-10/msg00008.html 
既然他们可能出问题,别人也可能出。更不用说,我写一个测试程序来测试某个语法特性,如果不包含任何头文件,使用NULL就不会通过。

 

事实上,我也同意说,大多数情况下,NULL都会被定义为0,这个大多数情况甚至可能是99.99%。问题在于,既然直接使用0可以100%解决问题(我们不需要include任何头文件,不需要考虑是不是兼容,不需要考虑有什么恶心事件的发生),为什么我们不直接用0呢?

btw:我最讨厌三种人,会数数的和不会数数的:D 
btw:“在MEM中有个地址转换表!空指针指向一个内核保留的只读地址!由MEM(内存管理)完成映射”,这没有踩到本质的点上。

 
 思一克 回复于:2005-05-19 11:51:10  
有谁可以给出C中空指针不用0地址的例子?

 
 win_hate 回复于:2005-05-19 13:00:31  
我不懂C++  说得很对。

不过把NULL 定义为别的东西,虽然不能比拟为犯法,但定性为道德败坏绝对是没有问题的。

我把我前面贴子中的

NULL 规定为一个现实定义的零指针常数

改为:

ANSI C 标准中所提及的 NULL 是一个现实定义的零指针常数

这样总没有问题了。其实,我们前面所讨论的NULL,指的正是编译系统提供的NULL,而不是自己另外定义的。

ps. 法律也会有漏洞,标准也会有自相矛盾的地方。

 
 我不懂C++ 回复于:2005-05-19 20:03:55  
我不太能够指出C语言里面NULL不等于0的情况,因为我对C其实不很了解。 
但是在C++里面,这肯定会是一个问题。这里的问题在于名字碰撞。C++倾向于尽量少用宏,而多用常量,这是因为常量的名字不会撞倒。 
譬如说我写一个SQL模块,里面我想定义一些标志位: 
namespace SQL 

enum Flags 

    NULL = 0, 
    LOCK, 
    ... 
}; 
// other definitions omitted 

那如果像现在这样,就会撞上,最终导致编译错误,所以我只能定义成:SQL_NULL。或许C语言里面这样做有理由,但是在C++里面,SQL::SQL_NULL就和CStudent::mStudentName一样,通常是不好的习惯。 
当然,NULL不可能成为一个常量,否则编译错误会更多。 
我想C++里面的新的关键字null之所以用小写,或许也考虑了一般人定义常量都是全大写(独家猜测:D)。 
我同意win_hate关于道德败坏的定义,但是标准只规定了某个政府部门不能道德败坏,并没有规定其它政府部门不能道德败坏......

_________________ 
愿耶稣基督、穆罕默德、释迦牟尼与你同在!

 
 bonnytan 回复于:2005-05-25 14:39:16  
许多程序设计风格的意见只是意见。通常卷入 ``风格战争" 是毫无意义的。某些问题 争辩的双方是不可能同意, 认同对方的不同或者是停止争论的。此为引用http://c-faq-chn.sourceforge.net/ccfaq/node286.html#q:17.10

 
 flw 回复于:2005-05-25 14:52:26  
[quote:afc7635823="bonnytan"]许多程序设计风格的意见只是意见。通常卷入 ``风格战争" 是毫无意义的。某些问题 争辩的双方是不可能同意, 认同对方的不同或者是停止争论的。此为引用http://c-faq-chn.sourceforge.net/ccfaq/node286.html#q:17.10[/quote:afc7635823] 
这不是一个风格战争。

BTW:拜托所有清完嗓子准备发言的朋友,先喝杯茶然后将别人的发言都看一遍, 
不要断章取义。

 
 sfi 回复于:2005-05-25 15:53:22  
建议不要在这里谈论风格问题,风格都是公司规定的。

现实生活中,null就是无、啥也没有的意思,可以向少林寺方丈请教一下。

 

在C语言中,NULL(stddef.h里定义为大写)表示一个无效的指针,但总要具体实现吧。所以[b:d975946d92][color=blue:d975946d92]许多[/color:d975946d92][/b:d975946d92]实现将其定义为(void *)0,stddef.h里就是这样定义的,有些也定义为0,两者在具体用到的时候效果一样。NULL表示[color=blue:d975946d92]无效指针[/color:d975946d92],但它不是无,因为它有自己的值。 
你可以改变NULL的定义,例如你可以重新定义 
#ifdef NULL 
#undef NULL 
#endif 
#define NULL (void *)1 
也就是说,系统规定的无效地址可能跟你定义的无效地址不一致,这时你的无效可能真的就无效了。

最后回答一下楼主的问题: 
p指向了一个[color=blue:d975946d92]被定义为无效[/color:d975946d92]的地址。

 
 leon_leon 回复于:2005-05-25 17:16:07  
学到知识了。

 
 asdmonster 回复于:2005-05-25 21:02:07  
我的一点理解加上刚才做的一个小实验,说出来请大家指点:

1,int * p; 
    当declare一个指针的时候(非函数指针),我在redhat9自带的gcc上看到的是编译器申请了一个空间,然后赋 $0,我没有明白这个 $0到底是代表了 $0 还是 NULL(in stdio.h)。


2,if(p) if(!p) 
     if()中出现的只能是逻辑变量,true or false,其实p经历了两次转换(cast):第一次转化为int,第二次转换是 (int)0 == false, 
     if(p)这样的写法建立在两个假设的基础之上的:第一,NULL宏被定义为 (void*)0,第二,计算机只有0,1,没有true,false,第二个假设就是false用0表示,而不是-1(我记得以前学习的时候遇到过这样的表示法) 
3,NULL 
      NULL表示的逻辑意义并不是 0(指针),而是[color=blue:66cc41fa4b]指向内容不确定(指针)[/color:66cc41fa4b] ,

个人觉得,无论规范怎么定义,if( NULL == p)要优于 if(p),后者除了习惯,几十年来c程序员中的习惯(不可否认习惯是程序的一部分),我看不出任何额外的益处。

当然,在林锐的书上这么写,要用 if( p) 而不是 if( NULL == p),面试的时候我也会告诉面试官 if(p),毕竟这样更c style一点。 :em11: 

哎。

 
 win_hate 回复于:2005-05-25 22:18:48  
请后继发贴者看清前面的贴子再接, 我把一些我认为正确的观点再写一下:

1、0 和 (viod *)0 是零指针常数 
2、0 或 (void *)0 转换为 (type *)0 后,称为零指针 
3、零指针与任何指向有效地址的指针比较一定不等 
4、stddef.h 中有一个标准的宏 NULL,该宏被规定为 实现定义的零指针常数.

以上 4 条均是 ANSI C 标准的规定,一个符合 ANSI 标准的编译器必须支持它们。根据以上4条,if (p) 与 if (p != NULL) 等价。

感谢 我不懂C++ 兄, 他指出,标准并未规定:你不可以用自己定义的 NULL 去覆盖 stddef.h 中的 NULL, 所以用 if (P == NULL)  不好。

我同意此观点的根据,但不同意其结论。NULL 的作用在于 [color=red:0b65db81b1]``提示此为一指针''[/color:0b65db81b1],是否用 NULL,是一个风格的问题。而且 NULL 的用法在 c 里已经是事实标准。


重定义 NULL 是很稀奇的事。如果你认为重定义一个宏没什么大不了,请注意 NULL 是一个 ANSI C 规定实现的标准宏。

重定义 NULL 与重定义标准库函数可以相提并论。与宏一样,函数库也并非语言的一部份,但 ANSI C 还是规定了一些标准库。没人可以禁止你实现自己的 printf,并覆盖 stdio 中的 printf,而你自己实现的 printf 可以调用一个 abort 使程序崩溃 。

 
 asdmonster 回复于:2005-05-25 22:35:44  
个人觉得: 
if( p )  不等于 if( NULL != p) 
因为有两种情况: 
1,ansi c的enhance(升级?)。 
2,某些标准和ansi c的不一致,比如 posix和ansi c的某些不一致。 
唯一能确定的是,有这么一个NULL存在,或者说NULL是定义,(void *)0是实现。

软件世界中没有none的概念, NULL想表达的是不确定而不是没有,就像 NULL != NULL一样。

恩,可能上面我的回复让人误解了。我想说的是这个。

 huang0610 回复于:2005-05-26 01:30:01  
坚决认为赋null而不是0,虽然c定义了null的值为0。具体为什么,我想听听谭老师的解释吧 
 “指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:p=null,实际上null是整数0,它使p的存储单元中所有二进位均为0,也就是使p指向地址为0的单元。系统保证使改单元不做他用(不存放有效数据),即有效数据的指针不指向0单元。实际上是先定义null,即:#define null  0.........p=null;  在<stdio.h>头文件中就有以上null的定义,它是一个符号常量,人们习惯上不用"p=0;"而是用"p=null;",这样可读性比较好” 
原文!!!

 
 kernelxu 回复于:2005-05-26 11:19:18  
[quote:208e343015="huang0610"]坚决认为赋null而不是0,虽然c定义了null的值为0。具体为什么,我想听听谭老师的解释吧


 “指针变量可以有空值,即该指针变量不指向任何变量,可以这样表示:p=null,实际上null是整数0,它使p的存储单元中所有二进..........[/quote:208e343015] 
老兄,说几点: 
1、是NULL不是null 
2、牛人说的不一定完全正确,可能有些系统0地址不写有效数据,但并不是说所有的系统0地址都不写有效数据,特别是在嵌入式系统中系统会榨干每一个bit的内存。 
3、同意win_hate老大

 
 aero 回复于:2005-05-26 11:21:27  
[quote:fb3f2c9c6e="kernelxu"] 
老兄,说几点: 
1、是NULL不是null 
2、牛人说的不一定完全正确,可能有些系统0地址不写有效数据,但并不是说所有的系统0地址都不写有效数据,特别是在嵌入式系统中系统会榨干每一个bit的内存。 
3、同意win_hate?..........[/quote:fb3f2c9c6e]

后面回帖的很多人,压根也没看前面大家辛辛苦苦的回帖。上来就说,丢脸的自是他们。兄不必与之计较,^_^,win_hate总结的的确非常好。

 
 mirnshi 回复于:2005-05-26 11:27:10  
如果仅仅声明一个指针,而没有任何赋值,那么这个指针是野指针,它会指到VM的任何位置,碰到异常操作,比如对只读区写操作,就会引起硬件中断产生core,也就是通常的段错误。 
良好的编程风格是将指针永远都可控,也就是这个指针的地址,程序可控,通常,对于不使用或初始的指针都将其地址置为0,这是约定俗成的,就如同,我们经常使用的进制一样,你非用一个别人都不用的进制表示数,那也随你,只是别人觉得怪而已。再比如,用free释放完指针后,相信大家都会将指针置成NULL或0,就是为了再使用这个指针时,便于判断。指针的地址为0,操作起来就非常方便,比较位操作等,都可对应到机器码,这也就体现了“高级汇编”的美誉。用NULL宏,仅仅是为了可读性,编译器会进行优化的。 
对于将NULL定义成某个地址,然后进行比较,相对NULL为0地址,然后比较,性质是相同的,在执行过程中,如果重新定义的地址为可操作,可能会对程序的逻辑流程产生影响。

另,谭老师的书,还是少看,会误人子弟,他的理解都是dos年代的,适合用tc2.0编程,32位的OS上,很多提法是不对的。

 
 kernelxu 回复于:2005-05-26 11:40:04  
aero老大说的即是! 
请求将此贴设为精华?! 
顶!

 
 wolf0403 回复于:2005-05-26 16:10:46  
在 TCPL 第二版中文版中 5.4 节地址算术运算 中有这样一句 (p86 line4) 
[quote:a1ed323f93]C 语言保证 0 不是数据的有效地址[/quote:a1ed323f93] 
还有下面 line6-7 
[quote:a1ed323f93]指针与整数不能相互转换,但0例外:常量0可以赋给指针……程序中经常使用符号常量NULL代替常量0,这样有助于更清楚地记住常量0是指针的一个特殊值[/quote:a1ed323f93]

根据这个说法,特殊的是0,而不是NULL:NULL只是常量0的一个助记符。不用说什么“某些平台不以0为特殊值”云云;如果要说,请给出明确的例证。否则,我还是更倾向于相信 Denies Ritchie 和 Brian Kernighan 在书中的断言。

ps,很奇怪的是,我在附录A中没有找到可以印证这个说法的条款。谁有 TCPL 第二版新版或者 C99 标准文档的,可以看看。

 
 stonejar 回复于:2005-05-31 17:06:30  
林锐的书没有说!ptr,只说了ptr==NULL和ptr!=NULL,别诬陷人家

 
 blazewater 回复于:2005-06-02 17:31:08  
林锐那本垃圾书也有人看,笑话,那里面错误一大堆; 
要看就看那些经典的书

 
 smileyg 回复于:2005-06-04 14:16:11  
同意FH的看法。NULL并不一定是0,有些程序员想当然用!ptr去判断指针是否为 
NULL。严格来说,这完全是一厢情愿的做法。在一些编译不严格的系统里面有可能能够编译通过,但是假如碰上相反的情况,我们又会去埋怨系统了。鄙人就碰上过类似的情况,最后把别人程序中的!ptr改成null完全搞定。所以说,养成良好的编程习惯,按照c语言的语法规则编写代码是解决类似问题的最好方法。

 
 高峰 回复于:2005-07-19 16:36:32  
这是一个哲学问题,在这里讨论不合适。

 
 AndyFastow 回复于:2005-07-20 05:12:51  
as time goes on,  
people think NULL == 0 is bad expression (in c) 
so... 
in Java We create a new nulltype, that is not a primitive type.

 
 SirFang 回复于:2005-07-20 10:37:54  
null是一个概念,NULL是这个概念的一个实现,NULL=0是实现的一个方法,但不是唯一的方法。

 
 mik 回复于:2005-07-20 14:34:28  
0 与 空(NULL) 在概念上是两码事

0 是实数,是一个实物数 
空 概念上是无,不包括任何东西,当然也不包括0啦.

以上阐述的是概念上的问题,

实际上: 在代码中没有什么分别. 定义上已经将 0 定义为 NULL,  
实际上也没必要分得那么细, 倒不如,实实在在的在代码算法等多思考

在 linux 及 windows 系统上编程不可能地避免使用它们的宏定义. 
这属于编程风格上的问题.

typedef struct date { 
        ...... 
       ..... 
} DATE;

DATE m_date1;

这样的代码风格,个人认为不好.

个人比较喜欢定义为:  struct date m_date1; 这样有利于理解变量本质..

而: char *p; p = NULL;

倒不如直接定义为: char *p = 0; 简单明了.....

 
 FH 回复于:2005-07-20 14:53:51  
[quote:d6e88395a3="mik"] char *p; p = NULL; 

倒不如直接定义为: char *p = 0; 简单明了[/quote:d6e88395a3]

malloc为什么不在失败的时候返回0而是返回NULL呢? 
为什么所有系统和标准函数对指针型都不是返回0而是返回NULL呢? 
到底哪个才是[color=red:d6e88395a3]简单明了[/color:d6e88395a3]的表述不是很清楚了吗? 
简单明了不是个人习惯!

 
 mik 回复于:2005-07-20 15:15:37  
[quote:ecba7bbefd="FH"]谋硎霾皇呛芮宄寺穑? 
简单明了不是个人习惯malloc为什么不在失败的时候返回0而是返回NULL呢?  
为什么所有系统和标准函数对指针型都不是返回0而是返回NULL呢?  
到底哪个才是简单明了的表述不是很清楚了吗?  
简单明了不是个人习惯!![/quote:ecba7bbefd]

char *p = (char *)malloc(sizeof(char) * N);

 

if (p == NULL)  与 if(!p) 效果一样

malloc 返回 是0 是 NULL 有什么区别???

 
 FH 回复于:2005-07-20 15:36:06  
谁说malloc返回0?哪份文档上写着?

 
 mq110 回复于:2005-07-20 15:43:59  
>>if (p == NULL)  与 if(!p) 效果一样 

以前FH 都讲的很清楚了. 又弄出来了..~~

 
 gvim 回复于:2005-07-20 15:55:00  
[quote:225068be76="FH"]谁说malloc返回0?哪份文档上写着?[/quote:225068be76]

对于NULL这个问题 不用说那么多了,这个问题不是简单的数学问题,象1+1=2可以讲明白。 
而如果固执的人 在对这个问提的本质上没有理解,仅仅从表面去理解与0有什么关系的话,你说这么多就象是对一群工科学生将哲学。你费再多的唇舌不过是对牛弹琴,虽然你讲的是更深一个层次的东西,可是他们不能体会。所以有些东西只可意会,不可言传呢 :mrgreen:  :mrgreen:

 
 mik 回复于:2005-07-20 16:03:47  
[quote:5609debd8d="FH"]谁说malloc返回0?哪份文档上写着?[/quote:5609debd8d]

malloc 分配不成功,不返回 0 返回什么?

返回NULL????

char *p = (char *)malloc(sizeof(char) * N); 
if (!p) 有错么?

 
 mq110 回复于:2005-07-20 16:07:18  
[quote:d0302e7551="mik"]

malloc 分配不成功,不返回 0 返回什么?

返回NULL????

char *p = (char *)malloc(sizeof(char) * N); 
if (!p) 有错么?[/quote:d0302e7551]

[quote:d0302e7551]For calloc() and malloc(), the value returned is a pointer to the allo- 
       cated  memory,  which  is suitably aligned for any kind of variable, or 
       NULL if the request fails.[/quote:d0302e7551]

 
 mik 回复于:2005-07-20 16:14:05  
[quote:bca921867b="mq110"][/quote:bca921867b]

 

本身 NULL 就是 0 的定义

返回 0 并没什么不妥


while (*p)   与 while (*p != '/0')  本质是一样的.只是风格与精简的问题.

*p = '/0';   与 *p = 0;  本质上也是一样的. 在编译器看来,并不分别.编译后,内

存单元都为 0

 
 mq110 回复于:2005-07-20 16:16:16  
谁告诉 你的NULL 是0??

我就此 保持沉默.  
你错误理解 与我无关.把你弄明白了 有我什么好处?

 
 gvim 回复于:2005-07-20 16:18:20  
[quote:7506918e07="mq110"]谁告诉 你的NULL 是0??

我就此 保持沉默.  
你错误理解 与我无关.把你弄明白了 有我什么好处?[/quote:7506918e07]

呵呵, 兄弟醒悟了。。。。 :mrgreen:  :m01:

 
 高峰 回复于:2005-07-20 16:20:47  
善哉善哉!都怪我,沉下去的帖子被我捅了起来。 
阿弥陀佛。

 
 mq110 回复于:2005-07-20 16:25:11  
[quote:9177d9c798="gvim"]

呵呵, 兄弟醒悟了。。。。 :mrgreen:  :m01:[/quote:9177d9c798]

兄弟 其实我挺爱帮助人的. 不过最近胡搅蛮缠的人比较多.

 
 mik 回复于:2005-07-20 16:25:18  
:) 算了不吵也罢, 我是从本质上看问题...

有些人初初看linux和unix内核源代码,不少人说代码是很难读懂....

并非是标准C... gcc本身就不完全是标准C....若linux一定要用标准C来写的话.那

就不是linux了

另一方面,也阻碍了C的发展

 
 surfzsl 回复于:2005-07-20 16:48:43  
[quote:84c11e69e3="mik"]

malloc 分配不成功,不返回 0 返回什么?

返回NULL????

char *p = (char *)malloc(sizeof(char) * N);

if (!p) 有错么?[/quote:84c11e69e3] 
man 3 malloc 
说的很明白 
有什么好争的

 
 gvim 回复于:2005-07-20 16:51:54  
[quote:92d4b7fe0d="mq110"]

兄弟 其实我挺爱帮助人的. 不过最近胡搅蛮缠的人比较多.[/quote:92d4b7fe0d]

呵呵,遇到讲道理,懂礼貌的谁都愿意帮,哪怕自己麻烦点。 
遇到“胡搅蛮缠”的,呵呵,还是及早醒悟的好。

 
 mike_chen 回复于:2005-07-20 16:53:12  
[quote:1d1e44f930="mik"]

malloc 分配不成功,不返回 0 返回什么?

返回NULL????

char *p = (char *)malloc(sizeof(char) * N); 
if (!p) 有错么?[/quote:1d1e44f930] 
malloc 分配不成功,当然是返回NULL了,man malloc!

 
 mike_chen 回复于:2005-07-20 17:00:15  
这个问题讨论的还真是激烈! :mrgreen:

 
 mik 回复于:2005-07-20 22:54:17  
在 linux 下, malloc 函数在 glibc 库中..

查看 glibc 下 malloc 的实现代码,可以得知:

代码中定义了:  
#define __malloc_ptr_t  (void *) 
.... 
#define NULL  ((__malloc_ptr_t)0) 
......

而 malloc 的实现代码中,出错时只是简单地 return 0;

也就是说简单地将 0 赋给了 __malloc_ptr_t  类型

整个源代码中,并没有看见过 return NULL;  
或是: return (__malloc_ptr_t)0; 之类的.

虽然,在malloc的手册上说明失败时返回 NULL: 
事实上,只是将0作为返回值...

 
 AndyFastow 回复于:2005-07-21 00:47:35  
NULL is a pointer,it is ambiguous using (void *)0 to express it 
in C. 
so, for the latest languages, people fixed it.

 
 z16304607 回复于:2005-07-23 19:25:07  
1,按照标准来说NULL和0是一样的int *p=new int(0)和int *p=new int(NULL)结果是一样的。

2,int *p=NULL和int *p=0;都是定义指针p并初始化指针p为指向0x00000000的地址(至少WINDOWS操作系统是这样的)。“0x00000000”此地址可理解为空地址。当然你也可以自己写个操作系统或编译器把该地址定为“0xFFFFFFFF",甚至更变态的地址

3,我们没有必要讨论NULL和0的区别。讨论不出结果的,因为操作系统,编译器已经做成这样子了。

char *p1=new char('1'); 
char *p2="123456"; 
cout<<p1<<endl;cout<<*p1<<endl;cout<<p2<<endl;cout<<*p2; 
char *p3="NULL";char *p3='0'; 
char *p3=NULL;   char *p3=0;

int *p6=0;int *p7=new int(0); 
cout<<p7<<endl; 
cout<<*p7<<endl; 
搞清楚以上这些就行了。 
int *p=0; 
int *p=1;//这个是错的;

 
 z16304607 回复于:2005-07-23 19:28:12  
char *p3='0';更正char *p3="0";

 
 technologier 回复于:2005-07-23 20:37:51  
我记得标准C++,提倡使用0而不是NULL

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台