void 在英文中作为名词的解释为 “空虚、空间、空隙”,而在 C 语言中,void 被翻译为**“无类型”,相应的void *** 为**“无类型指针”**。
void 似乎只有"注释"和限制程序的作用,当然,这里的"注释"不是为我们人提供注释,而是为编译器提供一种所谓的注释。
1.对函数返回的限定,这种情况我们比较常见。
2.对函数参数的限定,这种情况也是比较常见的。
一般我们常见的就是这两种情况:
void 类型指定没有可用的值。它通常用于以下三种情况下:
序号 | 类型与描述 |
---|---|
1 | 函数返回为空 C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status); |
2 | 函数参数为空 C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void); |
3 | 指针指向 void 类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。 |
int *a;
void *p;int main(){
char c = 'a';
char *pc = &c;
//void a;
void *p = &c;//万能指针 可以存储任何类型的地址
pc = p;
int i = 1;
int *pi = &i;
p = &i;
pi = p;
double d = 3.14;
double *pd = &d;
p = &d;
pd = p;
return 0;
}
p=a;
而 void * 则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换。
void *p1;
int *p2;
p1 = p2;
虽然如此,但这并不意味着可以无需任何强制类型转换就将 void 指针直接赋给其他类型的指针,因为“空类型”可以包容“有类型”,而“有类型”则不能包容“空类型”。例如:猫是动物,狗也是动物。但我们不能说,动物是猫,也不能说动物是狗。
void *p1;
int *p2;
p2 = p1;//错误
因此如果要将 void 指针 p 赋给其他类型的指针,则需要强制类型转换,就本例而言:p2=(int *)p1。
在内存的分配中我们可以见到 void 指针使用:内存分配函数 malloc 函数返回的指针就是 void * 型,用户在使用这个指针的时候,要进行强制类型转换,也就是显式说明该指针指向的内存中是存放的什么类型的数据 (int *)malloc(1024) 表示强制规定 malloc 返回的 void* 指针指向的内存中存放的是一个个的 int 型数据。
据资料的例子: char 型操作把指针的值加上了 sizeof(char) 字节,而 int 则是sizeof(int) 字节。
char a[20]="hello world";
int *p=(int *)a;
p++;
printf("%s", p);
所以语句“printf("%s",p)”将输出 “o world”。
而对于 void 指针,编译器并不知道所指对象的大小,所以对 void 指针进行算术操作都是不合法的
#include
int main(void)
{
void * p="HelloC";
p++;
printf("%s\n", p);
}
运行结果为:
elloC
void 几乎只有"注释"和限制程序的作用,因为从来没有人会定义一个 void 变量,让我们试着来定义:
void a;
这行语句编译时会出错。即使 void a 的编译不会出错,它也没有任何实际意义。
众所周知,如果指针 p1 和 p2 的类型相同,那么我们可以直接在 p1 和 p2 间互相赋值;如果 p1 和 p2 指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。
float *p1;
int *p2;
p1 = p2;
//其中p1 = p2语句会编译出错,
//提示“'=' : cannot convert from 'int *' to 'float *'”,必须改为:
p1 = (float *)p2;
小心使用 void 指针类型:
如果函数的参数可以是任意类型指针,那么应声明其参数为void *。
**注:**void 指针可以任意类型的数据,可以在程序中给我们带来一些好处,函数中形为指针类型时,我们可以将其定义为 void 指针,这样函数就可以接受任意类型的指针。如:
典型的如内存操作函数 memcpy 和 memset 的函数原型分别为:
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
这样,任何类型的指针都可以传入 memcpy 和 memset 中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型(参见 C 语言实现泛型编程)。如果memcpy 函数的参数类型不是 void*,而是 char*.
原文参考:https://www.cnblogs.com/wuyudong/p/c-void-point.html