多数指针带有类型信息,例如 int * 表示指向 int 的指针。当需要在不同时刻保存不同类型对象的地址,或编写与具体类型无关的接口时,可使用void 指针(void *)。本节说明其声明、赋值规则及与动态内存的关系。
类型不同的指针不能随意混赋
int i = 9;
int *p;
float *fp;
p = fp; /* 错误:类型不匹配 */
fp = &i; /* 错误:类型不匹配 */不同对象类型的指针之间不能直接赋值,除非经过兼容的类型转换。
void 指针的声明与赋值
void * 可保存任意类型对象的地址,且可将 void * 赋给任意类型的指针而不必显式转换(C 标准允许):
void *ptr;
int *p;
float *fp;
int i = 9;
ptr = p;
ptr = fp;
ptr = &i;
p = ptr; /* void * 赋回 int * */void 指针的大小
指针大小由平台决定,与所指类型无关:
#include <stdio.h>
int main(void) {
void *ptr = NULL;
int *p = NULL;
char *cp = NULL;
float *fp = NULL;
printf("void * 的大小 = %zu\n", sizeof(ptr));
printf("int * 的大小 = %zu\n", sizeof(p));
printf("char * 的大小 = %zu\n", sizeof(cp));
printf("float * 的大小 = %zu\n", sizeof(fp));
return 0;
}解引用前须转换为具体类型
void * 不携带元素类型信息,不能直接对 *ptr 读写,应先转换为相应类型的指针再解引用:
#include <stdio.h>
int main(void) {
int a = 56;
float b = 4.5f;
char c = 'k';
void *ptr;
ptr = &a;
printf("a 的值为: %d\n", *((int *)ptr));
ptr = &b;
printf("b 的值为: %f\n", *((float *)ptr));
ptr = &c;
printf("c 的值为: %c\n", *((char *)ptr));
return 0;
}同一 void * 变量可先后指向不同类型对象,读取时必须与当前实际类型一致,否则属于未定义行为。
常见用途
- 动态内存:
malloc、calloc等返回void *,再赋给具体类型指针,见动态内存分配。 - 通用接口:如标准库
qsort的比较函数通过const void *传递元素地址,由用户按元素类型解释。
int *x = (int *)malloc(sizeof(int));
if (x != NULL) {
*x = 90;
printf("%d\n", *x);
free(x);
}void * 用于存放“某处内存的地址”;真正读写时须恢复为正确的指针类型。掌握这一点有助于理解动态分配与部分标准库函数的设计。