普通指针都有类型,int 指针只能指 int。但有些场景你压根不知道会用哪种类型,这时 void 指针出场了。下面看它是什么、怎么用、一般拿来干嘛。
问题:指针类型卡得死
之前我们见过的指针,地址和声明类型必须匹配:
int i = 9; // 整型变量
int *p; // 整数指针
float *fp; // 浮点指针
p = fp; // 错误:类型不匹配
fp = &i; // 错误:类型不匹配int 指针不能指 float 变量,反之亦然。为了打破这种限制,C 语言提供了 void 指针。
void 指针是什么
void 指针是不限定类型的通用指针,可以保存任何数据类型的地址:
void *ptr; // void 指针声明地址可以被赋给它,也能赋回任意类型的指针,都不用显式类型转换:
ptr = p; // 正确
ptr = fp; // 正确
ptr = &i; // 正确void 指针的大小
void 指针的大小和字符指针一样,具体字节随平台变(32 位一般是 4,64 位一般是 8):
#include <stdio.h>
int main() {
void *ptr = NULL; // void 指针
int *p = NULL; // 整型指针
char *cp = NULL; // 字符指针
float *fp = NULL; // 浮点指针
printf("void指针的大小 = %d\n", sizeof(ptr));
printf("整型指针的大小 = %d\n", sizeof(p));
printf("字符指针的大小 = %d\n", sizeof(cp));
printf("浮点指针的大小 = %d\n", sizeof(fp));
return 0;
}所有指针的大小都一样,指针存的只是一个地址。
void 指针解引用前要转回原类型
void 指针不知道自己到底指着什么,所以直接 *ptr 是错的,必须先转回原类型再解引用:
#include <stdio.h>
int main() {
int a = 56; // 初始化一个整数变量
float b = 4.5; // 浮点变量
char c = 'k'; // 字符变量
void *ptr; // 声明 void 指针
// 给变量 a 分配地址
ptr = &a;
printf("a 的值为 : %d", *((int *)ptr));
// 给变量 b 分配地址
ptr = &b;
printf("\nb 的值为 : %f", *((float *)ptr));
// 给变量 c 分配地址
ptr = &c;
printf("\nc 的值为 : %c", *((char *)ptr));
return 0;
}输出:
a 的值为 : 56
b 的值为 : 4.500000
c 的值为 : k同一个 void 指针先后指向 int、float、char,读取时各自转回对应类型。
void 指针有什么用
- malloc()/calloc() 返回 void 指针:动态内存分配函数返回 void*,可以赋给任何类型的指针(通常写成
(int *)malloc(...)),这是它最常见的用途。 - 实现泛型函数:参数用
void *,一套代码接收任意类型的数据。比如 qsort() 的比较函数、pthread 的线程函数参数统统是 void*。 - 可重用性:void 指针能存任何类型的对象地址,配合适当类型转换即可取出。
// malloc 返回 void*,赋给 int*
int *x = (int *)malloc(sizeof(int));
*x = 90;
printf("%d", *x); // 90void 指针是不知道里面装什么的通用指针,随便收地址,但解引用前必须转回原类型;malloc 和泛型函数全靠它。