首先说一下什么是指针,只要明白了指针的含义,你就明白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、指针操作超越了变量的作用范围。这种情况让人防不胜防。======================================================【转载】空指针赋值分区为什么通过空指针读写的时候就会出现异常?- 除了NULL表示空指针,是否还有其他的值也是空指针?
- 如果还有其他的值,你们这些表示空指针的值都是什么?为什么?
首先解答第一个问题,在windows核心编程第四版的windows的内存结构一章中,表13-1有提到NULL指针分配的分区。其范围是从0x00000000到0x0000FFFF。这段空间是空闲的,对于空闲的空间而言,没有相应的物理存储器与之相对应,所以对这段空间来说,任何读写操作都是会引起异常的。有了上面的解答后,第二个问题就很容易解答了。NULL的定义出现以下几个地方:stdio.h文件中#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endifiOS.h文件中#ifndef NULL
#define NULL 0
#endifwindef.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开始分配,故空指针的区间范围有那么大。 =============================================================
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
因此,本人在此再次强调,不要自?.........[/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
说到空,就想到了空即是 {MOD}, {MOD}即是空了.题外了.
对于返回,还是以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。
一周热门 更多>