NULL 在C语言中定义为:
#define NULL ((void *)0) 把地址0转换成指针类型,称为空指针
它的特殊之处在于,操作系统不会把任何数据保存在地址0及其附近,也不会把地址0~0xfff的页面映射到物理内存,所有对地址0的访问都会立刻导致段错误
*p=0会导致段错误,就像放在眼前的炸弹一样很容易找到,相比之下,野指针的错误就像埋下地雷一样,更难发现和排除,这次走没事,下次走就有事
void *指针与其他类型的指针之间可以隐式的转换,而不必用类型转换运算符。注意,只能定义void *指针,而不能定义void型的变量,因为void *型指针和别的指针一样都占4个字节,而如果定义void型的变量,编译器不知道该分配几个字节给变量。
void *指针不能直接Dereference(指针所指的值),而必须先转换成别的类型的指针在做Dereference。
void func(void *pv)
{
/* *pv ='A' is illegal */
char *pchar = pv;
*pchar = 'A';
}
int main(void)
{
char c;
func(&c); //传递的只能是指针
}
void指针使用规范
- void指针可以指向任意类型的数据,亦可用任意数据类型指针对void指针赋值,例如
int *print;
void *pvoid;
pvoid = print;
print = (int *)pvoid; //在将pvoid赋给其他类型的指针时需要强制类型转换
void 函数参数和函数返回进行限定
- 当函数不需要返回值时,必须使用void,void func(int,int);
- 当函数不接受参数时,必须使用void,int func(void);
void*可以指向任意类型的数据,因此可以用void*作为函数形参,这样的函数可以接受任意类型数据的指针作为参数:void *memcpy(void *dest,const void *src,size_t len);
当要访问void指针的值时,需要将其强制转为其他类型才能访问,因为它表示的内存地址,不能直接访问
函数指针
对于一个函数而言,函数名也是指向函数第一条指令的常量指针。而编译器要做的就是在程序编译之后,为每个函数分配一个首地址,即该函数第一条指令的地址。一般情况下,我们可以用一个指针来保存这个地址,而这个指针就是函数指针,该指针可以看作是它指向函数的别名,所以我们可以用该指针来调用这个函数。
type (*func)(type &, type &) 此语句声明一个指针func,它指向一个函数,函数带两个type型参数并返回一个type值
- 一个指向函数的指针必须确保被定义且分配了内存,否则它将指向一个空地址
- 特别注意第一个括号位置,如果我们不写括号:
type *func(type,type),这就不是一个指向函数的指针了,而是声明了一个函数,该函数返回一个type类型的指针
例子:
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
int (*func)(int,int); //声明函数指针,指向返回类型为int
int main()
{
func = max;
int c = (*func)(1,2);
func = min;
c = (*func)(1,2);
}
说明:func是一个函数指针,那么func就是指向该指针所指向的函数地址,所有(*func)(int,int)就是调用该函数的方式,ANSI C标准允许程序员将上式简写为func(),但是一定要记住这种写法只是一种简写形式
在表达式(func)()中,func两侧的括号很重要的
- func 是一个函数指针
- func()是(*func)()的简写形式
- &func是&(*func)的简写形式