指针指向的是内存中的一个地址,对于指针的操作通常包括解引用和算数运算
指针的解引用是从指针指向的地址开始向后读取,读取的长度为指针的类型,例如,int型指针解引用时向后读取4个字节,double型则是向后读取8个字节。
指针的运算,比如
int *a;
a++;
这个操作是将指针指向的地址向后移了一个数据类型对应的长度,这个例子中,指针向后移了sizeof(int)这么多个字节
同样void指针也是指向一块存储区域的开头,只不过它没有固定的类型。
一方面,由于没有固定的数据类型,所以可以不用强制类型转换地将其他类型的指针值赋给void指针。
int n = 10;
int* a = &n;
void* b;
b = a;
这个其实比较容易理解,指针指向的是一个数据块的开头,又由于void指针没有类型限制,所以可以将其他数据类型的指针的地址传给void指针。
另一方面,之前说的对于指针的解引用和算术运算都需要依赖于指针的实际类型,所以一般来说对于void指针,直接对其解引用和算数运算都是无效的。可以理解为没有数据类型,编译器无法知道该如如何获取指针指向的地址之后的数据。比如对b进行解引用
*b;
或者进行算数运算
b++;
编译器都会报错
expression must be a pointer to a complete object type
对于void指针,如果需要将其拿出来用的话,需要对其进行强制转换
char *c = (char*)b;
虽然一般编译器下对void指针是没法直接进行操作的,但是GNU编译器处理void指针的时候是将其当成char指针在处理
b++;
这句话的结果是对指针的地址加1
比如我们平时用到的memset,memcpy函数,其参数都是void指针
void*memcpy(void*dest,constvoid*src,size_tlen);
void*memset(void*buffer,intc,size_tnum);
使用void指针,可以保证处理的数据类型包容性更广,但是在使用的时候需要注意处理前后的数据类型。