void与null
void
void一般用在两种情况下。第一种情况是,如果函数没有返回值或参数,那么应该声明为void,不同的编译器会对省略的定义有所不同的解释,这种显示的定义明显可以提高程序的平台移植性。例如下面定义了一个没有传入参数、没有返回值的一个函数void func(void)
。如果返回值得类型不用void指定,有的编译器会默认返回得是一个int类型,这样就会造成一些潜在得移植错误。
第二种使用void得情况是声明一个void类型得指针:void* vp
。对于void类型指针,它只保存一个地址,不包含指向变量的类型信息,所以任何类型的指针都可以直接赋值给它,无需进行强制类型转换。
void类型指针一般用在函数的参数和返回之中,以达到泛型的目的,目的就是使一个函数能够处理更多的类型。例如malloc函数就返回一个void类型指针,同理,memcpy和memset两个函数也使用void类型指针来达到泛型的目的。这样,任何类型的指针都可以传入memcpy和memset中,这也真实体现了内存操作函数的意义,因为它操作的对象仅仅是一块内存,并不关心这块内存中保存的是什么类型。
void * malloc(size_t size);
void * memcpy(void *dest, const void *src, size_t len);
void * memset(void * buffer, int c, size_t num);
void类型指针虽然可以用来达到泛型的目的,但是它也包含一些风险,这种风险主要是丢失了类型的信息。如果有类型信息,编译器可以帮助我们进行类型匹配检查。下面程序中把一个int型的指针赋值给一个float类型,类型并不匹配,所以编译并不会通过。
void test(int* pi)
{
float *pf = pi; // 编译出错
}
int i = 5;
test(&i);
当你把int型地址复制给void类型指针,类型信息丢失了。在test2函数内部,当你把void类型强制转换成float类型的指针时,编译器并不进行任何类型匹配的检查。编译通过,但是pf指针指向的地址并不包含你期望的浮点数,所以往往会产生一些奇怪的错误。
void test2(void* pi)
{
float *pf = (float*)pi; // 编译通过
}
int i = 5;
test2(&i);
NULL
与void类型指针不同,NULL不是指针的类型,而是用来描述指针的值。一般情况下NULL被定义为0。如果定义int *p = NULL;
的话,就意味着p没有指向任何地址。这样就是安全的,NULL对暂时不用的指针变量赋初值,以避免产生野指针的问题。NULL也用在一些函数的返回中,如果返回的是NULL,那么就代表函数调用并没有返回成功,如fopen
函数以及fgets
函数等等。
还没有评论,来说两句吧...