下面代码摘自 stdlib.h
#ifdef __cplusplus #define NULL 0#else #define NULL ((void *)0)#endif当然,就机器内部而言,NULL指针的实际值可能与此不同,这种情况下,编译器将负责零值和内部值之间的翻译转换 。
NULL指针的概念非常有用,它给了你一种方法,表示某个特定的指针目前并未指向任何东西 。例如,一个用于在某个数组中查找某个特定值的函数可能返回一个指向查找到的数组元素的指针 。如果没找到,则返回一个NULL指针 。
在内存的动态分配上,NULL的意义非同凡响,我们使用它来避免内存被多次释放,造成经常性的段错误(segmentation fault) 。一般,在free或者delete掉动态分配的内存后,都应该立即把指针置空,避免出现所以的悬挂指针,致使出现各种内存错误!例如:
文章插图
free函数是不会也不可能把p置空的 。像下面这样的代码就会出现内存段错误:
文章插图
因为,第一次free操作之后,p指向的内存已经释放了,但是p的值还没有变化,free函数改不了这个值,再free一次的时候,p指向的内存区域已经被释放了,这个地址已经变成了非法地址,这个操作将导致段错误的发生(此时,p指向的区域刚好又被分配出去了,但是这种概率非常低,而且对这样一块内存区域进行操作是非常危险的!)
但是下面这段代码就不会出现这样的问题:
文章插图
因为p的值编程了NULL,free函数检测到p为NULL,会直接返回,而不会发生错误 。
这里顺便告诉大家一个内存释放的小窍门,可以有效的避免因为忘记对指针进行置空而出现各种内存问题 。这个方法就是自定义一个内存释放函数,但是传入的参数不知指针,而是指针的地址,在这个函数里面置空,如下:
文章插图
结果:
文章插图
my_free调用了之后,p的值就变成了0(NULL),调用多少次free都不会报错了!
另外一个方式也非常有效,那就是定义FREE宏,在宏里面对他进行置空 。例如
文章插图
执行结果同上面一样,不会报段错误:
文章插图
(关于内存的动态分配,这是个比较复杂的话题,有机会再专门开辟一章给各位讲述一下吧,写个帖子还是很花费时间和精力的,呵呵,写过的童鞋应该都很清楚,所以顺便插一句,转帖可以,请注明出处,毕竟,大家都是本着共享的精神来讨论问题的,写的好坏都没有向你所要什么,请尊重每个人的劳动成果 。)
指向空,或者说不指向任何东西 。
坏指针
指针变量的值是NULL,或者未知的地址值,或者是当前应用程序不可访问的地址值,这样的指针就是坏指针 。
不能对他们做解指针操作,否则程序会出现运行时错误,导致程序意外终止 。
任何一个指针变量在做解地址操作前,都必须保证它指向的是有效的,可用的内存块,否则就会出错 。
坏指针是造成C语言Bug的最频繁的原因之一 。
??????下面的代码就是错误的示例 。void opp(){ int*p = NULL; *p = 10; //Oops! 不能对NULL解地址}
void foo(){ int*p; *p = 10; //Oops! 不能对一个未知的地址解地址}
void bar(){ int*p = (int*)1000; *p =10; //Oops! 不能对一个可能不属于本程序的内存的地址的指针解地址}
void*类型指针
由于void是空类型,因此void*类型的指针只保存了指针的值,而丢失了类型信息,我们不知道他指向的数据是什么类型的,只指定这个数据在内存中的起始地址 。
如果想要完整的提取指向的数据,程序员就必须对这个指针做出正确的类型转换,然后再解指针 。因为,编译器不允许直接对void*类型的指针做解指针操作 。
虽然从字面上看,void的意思是空,但是void指针的意思,可不是空指针的意思,空指针指的是上面所说的NULL指针 。
void指针实际上的意思是指向任意类型的指针 。任意类型的指针都可以直接赋给void指针,而不需要进行强制转换 。
推荐阅读
- 超炫酷技巧!C语言代码优化的技巧
- C语言访问字符串数组元素的方式
- C语言关键字const和指针结合的使用
- 头昏脑胀怎么治疗?
- C语言厉害在哪?
- C语言、嵌入式重点知识:回调函数
- C语言指针经典知识汇总
- 移动应用开发的六大编程语言
- 用C语言编写CPU使用率限制程序
- 跨平台的C语言网络框架库acl