6.8.2 void 类型指针
第 4 章中,在定义函数时,如果没有返回值,就会将返回值类型定义为 void,如果函数没有参数,也可以在参数列表中使用 void。在 C 语言中,void 表示空类型。因此,C 语言不允许定义 void 类型的变量,但是,C 语言允许定义 void 类型的指针。例如:
void *pv;
上述语句定义了一个 void 类型的指针变量 pv。
C 语言中,任何类型的指针都可以被隐式地转换为 void 类型的指针。也就是可以直接将一个其他类型的指针赋值或初始化给 void 类型的指针。例如:
int a = 10; int *pi = &a; void *pv = pi;
以上语句首先定义了一个 int 类型变量 a,并初始化为 10;接着,定义一个 int 类型指针变量 pi,并将变量 a 的内存地址初始化给 pi;最后定义一个 void 类型的指针变量 pv,并将 pi 的值初始化给 pv。这是没问题的,编译器可以将一个 int 类型的指针 pi 的值转换成一个 void 类型的指针初始化给 pv。因此,指针 pv 也保存着变量 a 的内存地址。
那可不可以对 pv 进行解引用,访问并获取变量 a 的值呢?例如:
printf("%d\n", *pv);
编译程序时,会有如下的警告和错误信息:
warning: dereferencing 'void *' pointer printf("%d\n", *pv); error: invalid use of void expression
警告信息内容为:在 printf 函数中,我们对 void 类型的指针进行了解引用;而错误信息内容为:无效地使用了 void 表达式。也就是说,不能对 void 类型的指针进行解引用。
对指针进行解引用时,会根据指针的类型来确定所访问的内存字节数和数据格式。由于 void 是空类型,没有内存大小和数据格式信息,因此,无法对 void 类型的指针进行解引用。
使用时,需要将 void 类型的指针再次转换为 int 类型的指针,才能正确访问变量 a。例如:
printf("%d\n", *(int*)pv);
在 pv 前面加上类型转换运算符进行强制类型转换,得到一个 int 类型的指针,对这个 int 类型指针再进行解引用就可以访问到变量 a,并打印输出值。
编译运行程序,结果如下:
10
void 类型的指针,通常都是作为函数的参数来使用,这样做的好处是,可以将任何类型对象的指针传递给它,并且 void 类型的指针可以像 char 类型的指针一样来进行指针的移动或指针的运算。即 void 类型的指针每移动一次,其保存的内存地址值就会增加 1 字节,而 void 类型的指针与某整数相加,所产生的新指针的内存地址就是原指针的内存地址与整数相加的和。
在“string.h”头文件中,有几个以“mem”开头的函数,都是以内存为操作对象的功能函数。例如 memset 函数可以以字节为单位设置指定大小的内存块数据,它的函数原型如下:
void* memset(void* buffer, int ch, size_t count);
函数第一个参数 buffer 表示所需设置内存块的起始地址;第二个参数 ch 是一个整数值,内存块的各字节都会被设置为该值;第三个参数 count 是一个无符号整数,表示内存块的大小,以字节为单位。结合起来看,memset 函数的功能是将一个从 buffer 地址开始的、count 字节大小的内存块中的各字节都设置为整数值 ch。函数返回值与 buffer 一样,同是该内存块的起始地址。
可以使用 memset 函数非常方便地将一个数组中的所有元素值全部设为 0。程序代码如下:
程序代码中,首先定义了一个长度为 5 的 int 类型数组 arr,并对数组进行了初始化。接着使用 memset 函数对数组进行设置,它会将数组 arr 看成是一个内存块,内存块的起始地址是 arr,内存块大小为数组的大小,内存块的各字节都会被设置为 0。因此,通过循环打印数组元素时,所有的数组元素全部都变为 0 了。
编译运行程序,结果如下:
0 0 0 0 0
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论