做了一道题,虽然问题的侧重点不在于指针,但是引发了我对一些指针相关内容的思考,发现自己没有真正地去认真思考这些问题……在此做个了断。
被释放的指针
当动态内存分配的时候,用完指针,就要将其释放掉,delete和free函数一样,不修改它参数对应指针指向的内容,也不修改指针本身,只是在堆内存管理结构中将指针指向的内容标记为可被重新分配。就是告诉系统这个地址的内存我已经不用了,系统可以重新分配给别的程序了,这个地址的值当然不会变。
如果不考虑多任务或多线程的影响(即紧跟在delete或free后不会发生其它任务或线程调用new或malloc之类的在堆上分配内存的函数),不把指针设为NULL是可以的。但是如果你不巧再new/malloc申请分配到这块内存,就会发生不可预知的情况。
所以释放后的指针为保证安全,要将其设为NULL,否则容易导致野指针的出现。
PS:至于网上很多说法是释放掉以后就把这块内存归还给系统,这个空间是不合法的或者是不属于这个程序的……这种说法就无法解释“为何释放了指针内存空间还是能对指针赋值和输出指针”的现象了。
空指针(NULL)
对于空(null)指针的概念,在 C 标准中明确地定义:值为 0 的整型常量表达式,或强制(转换)为“void*”类型的此类表达式,称为空指针常量。0、0L、'\0'、3-3、0*17以及(void*)0等都是空指针常量。
int* p;
p = 0、0L、'\0'、3-3、0*17以及(void*)0;
指针变量 p 经过上面任何一种赋值操作之后都将成为一个空指针。
空指针表示“未分配”或者“尚未指向任何地方”。它与未初始化的指针有所不同,空指针可以确保不指向任何对象或函数,而未初始化指针可能指向任何地方。
为了让程序中的空指针使用更加明确,从而保持统一的编程风格,标准 C 专门定义了一个标准预处理宏 NULL,其值为“空指针常量”,通常是 0 或者“((void*)0)”。
而为了区分整数 0 和空指针 0,当需要其他类型的 0 时,即使可能工作,也不能使用 NULL。NULL是空指针的一个别名。
PS:其实空指针和NULL指针有一定区别,通俗点来说NULL指针可以确保是0,但空指针却不一定是0,因为有可能为void*类型。
void指针
void 指针是一种特殊的指针,表示为“无类型指针”,任何类型的指针都可以直接赋值给 void 指针,而无需进行其他相关的强制类型转换,虽然如此,但这并不意味着可以无需任何强制类型转换就将 void 指针直接赋给其他类型的指针,要进行强制类型转换。
避免对void指针进行算数运操作:
ANSI C 标准规定,进行算法操作的指针必须确定知道其指向数据类型大小,也就是说必须知道内存目的地址的确切值。而对于 void 指针,编译器并不知道所指对象的大小,所以对 void 指针进行算术操作都是不合法的。所以会报错,但GNU标准指定"void*"的算法操作和"char*"一致,因此不会报错,但是在真是的设计环境中应该尽可能地符合ANSI标准,尽量避免对void指针进行算数操作。
如果函数的参数可以是任意类型的指针,应该将其参数声明为void*。