C语言 — void的用法解析[通俗易懂]
一、简介
void 中文翻译为”无类型”,有的也叫”空类型”。常用在程序中对定义函数的参数类型、返回值、函数中指针类型进行声明。
二、用法
首先应该注意一点的是void类型是不同于其他常见类型的,即void 类型不能够用来申明变量和常量。因为我们申明变量的时候需要明确告诉编译器,该变量是什么类型,比如说是int 或 char类型,这样编译才好为这个变量去分配存储空间,但你不能告诉编译器说我这是一个”空类型”,这样的话编译器肯定不会干的,自然你编译的时候会报错: "illegal use of type 'void'"
。
总的来说,void应用最广泛的就是跟指针结合,而void和指针的结合也大大扩展了指针的可能性。
void *
/*无类型指针,也称为空指针,可以指向任何类型的数据 *注意一点:当我们需要使用void 类型的的指针变量去指向某一类型的变量的时候,必须要对其进行类型转换 */
我们在定义一个指针变量的时候第一件事就是指定我们指针变量所指向的变量的类型。一旦被指定,我们的指针变量就只能指向这一类型的变量,即只能保存这一类变量的地址。之所以这样呢,是跟我们计算机的存储数据的形式有关。简单来讲,就是不同类型的变量被分配的内存大小是不一样的,当对指针变量去进行解引用的时候,就必须保证可以取出来正确的内存内容。
第一点,我们先看一个例子,这里有一个典型的应用案例就是malloc函数,我们经常会使用到的内存申请函数。请看一个小例子:
int *p_int;
p_int = (int *)malloc(sizeof(int));
先要说明一点的是,malloc()分配了内存,但没有为它指定名字,但是它却可以返回那块内存第一个字节的地址。因此,可以把那个地址赋值给一个指针变量,并使用该指针来访问那块内存。因为char代表一个字节,所以传统用法上曾将malloc()返回值定义为指向char的指针类型。然而,ANSIC标准使用了一个新类型:指向void的指针。这一类型被用作“通用指针”。
因为malloc分配内存返回的是一个void 类型的指针,所以我们在使用的时候通常会对该指针类型进行强制转换为我们所需要的的指针类型。这样我们就可以使用malloc()来为我们分配任意大小的内存空间(当然了,因为malloc是在堆区分配的内存,所以我们申请的这块内存的大小应该小于堆区的大小)。
我们知道两个指针变量p1,p2,只有当它们类型相同的时候才能进行互相赋值。如果p1,p2指向不同的数据类型,那么他们必须进行类型转换才能相互赋值。比如:
float *p1;
int *p2;
p1 = p2;
执行上面一段程序的时候我们会发现会报错,提示”cannot convert from 'int*' to 'float *
`”,若改为
int *p1;
void *p2;
p1 = p2;
此时就不会报错,因为赋值运算符的右边进行了隐式类型转换
。当然了,我们也可以进行强制类型转换,即使用括号进行类型转换,比如:
int *p1;
void *p2;
p1 = (int *)p2;
从上面的例子可以看出,当我使用void去修饰指针的时候,这种通用类型的指针可以很方便的和其他类型的指针之间进行相关转换。
void另一个重要的应用则就是跟函数进行结合主要有以下两个方面的应用。
- 对函数返回的限定;
- 对函数参数的限定;
三、总结
-
如果函数没有返回值那么应声明为void 类型
C语言中有一个规则,凡是不加返回值限定的函数,就会被编译器作为整型值(int)处理。但是许多人却误以为其为void类型。
因为C语言不像C++那样有很严格的类型安全检查。所以为了避免混,对于任何函数必须制定其返回值类型。如果函数没有返回值一定要声明为void类型。这样既可避免混淆也方便自己和别人查看我们的代码。
-
如果函数无参数,那么应该声明其参数为void
如果我们所写的函数不接受任何参数,那么一定要指明其参数为void。
-
如果函数的参数可以是任意类型指针,那么应声明其参数为void *
这里有几个比较常用到的函数,都采用了此规则。同样,这一规则在我们日常编程中应用也很广泛。
/* 内存操作函数 */ void *memcpy(void *dest, const void *src, size_t len); void memset(void *buffer, int c , size_t num); int memcmp(const void *sl, const void *s2, size_t n); /* 内存分配与释放函数 */ void *malloc(size_t size); void *calloc(size_t num, size_t size); void *realloc(void *ptr, size_t size); void free(void*ptr);
可以看到我们用void 来修饰了函数参数类型,即我们可以传任意类型指针。这也体现内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存存储的数据是什么类型。
-
使用void类型指针时应该注意
按照C标准规定,我们不能对void型指针进行运算。对有类型的指针进行算法操作的时候我们知道,因为其有具体所指向的类型,所以对其的运算是以其所指向的数据类型为单位进行的。而void的含义为空或者说无类型,所以就无法对其进行算术运算。
运行结果为:
我们如果要对void类型指针进行算术运算的话就必须进行类型转换,这里有一个典型的应用案例就是malloc函数,我们经常会使用到的内存申请函数。请看一个小例子:
先要说明一点的是,malloc()分配了内存,但没有为它指定名字,但是它却可以返回那块内存第一个字节的地址。因此,可以把那个地址赋值给一个指针变量,并使用该指针来访问该块内存。因为malloc分配内存返回的是一个void 类型的指针,所以我们在使用的时候通常会对该指针类型进行强制转换为我们所需要的的指针类型。
-
void 不能代表一个真实的数据类型
这个前面提到过,因为void在C语言中解释为
空
,或者无类型
,所以它当然无法代表一个真实的数据类型了。不过我们可以对其进行类型转换,这样它又可以变成各种各样的数据类型,所以我们可以将其理解成一个”抽象数据类型“。