C语言 — void的用法解析[通俗易懂]

C语言 — void的用法解析[通俗易懂]C语言-void的用法解析简介​ void中文翻译为”无类型”,有的也叫”空类型”。常用在程序中对定义函数的参数类型、返回值、函数中指针类型进行声明。用法​ void应用最广泛的就是跟指针结合,即void* //无类型指针,也称为空指针,可以指向任何类型的数据 //注意一点:当我们需要使用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另一个重要的应用则就是跟函数进行结合主要有以下两个方面的应用。

  1. 对函数返回的限定;
  2. 对函数参数的限定;

三、总结

  1. 如果函数没有返回值那么应声明为void 类型

    C语言中有一个规则,凡是不加返回值限定的函数,就会被编译器作为整型值(int)处理。但是许多人却误以为其为void类型。

    因为C语言不像C++那样有很严格的类型安全检查。所以为了避免混,对于任何函数必须制定其返回值类型。如果函数没有返回值一定要声明为void类型。这样既可避免混淆也方便自己和别人查看我们的代码。

  2. 如果函数无参数,那么应该声明其参数为void

    如果我们所写的函数不接受任何参数,那么一定要指明其参数为void。

  3. 如果函数的参数可以是任意类型指针,那么应声明其参数为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 来修饰了函数参数类型,即我们可以传任意类型指针。这也体现内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存存储的数据是什么类型。

  4. 使用void类型指针时应该注意

    按照C标准规定,我们不能对void型指针进行运算。对有类型的指针进行算法操作的时候我们知道,因为其有具体所指向的类型,所以对其的运算是以其所指向的数据类型为单位进行的。而void的含义为空或者说无类型,所以就无法对其进行算术运算。
    在这里插入图片描述
    运行结果为:
    在这里插入图片描述

    我们如果要对void类型指针进行算术运算的话就必须进行类型转换,这里有一个典型的应用案例就是malloc函数,我们经常会使用到的内存申请函数。请看一个小例子:
    在这里插入图片描述
    先要说明一点的是,malloc()分配了内存,但没有为它指定名字,但是它却可以返回那块内存第一个字节的地址。因此,可以把那个地址赋值给一个指针变量,并使用该指针来访问该块内存。

    因为malloc分配内存返回的是一个void 类型的指针,所以我们在使用的时候通常会对该指针类型进行强制转换为我们所需要的的指针类型。

  5. void 不能代表一个真实的数据类型

    这个前面提到过,因为void在C语言中解释为,或者无类型,所以它当然无法代表一个真实的数据类型了。不过我们可以对其进行类型转换,这样它又可以变成各种各样的数据类型,所以我们可以将其理解成一个”抽象数据类型“。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/144660.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • signed apk error [WifiManagerLeak]

    signed apk error [WifiManagerLeak]

    2021年9月30日
    44
  • 解析数据中心监控系统功能作用

    解析数据中心监控系统功能作用数据中心机房监控系统是什么?其主要功能作用有哪些?下面机房监控系统厂家-深圳计通小编就拿计通机房监控来举例:为保证机房的安全、稳定和高效运行,保证网络设备良好的运行状态和设备使用寿命与安全,从而实现用户的最大投资效益。机房监控系统对网络运行环境的电力供应、温度、湿度、漏水、空气含尘量等诸多环境变量,UPS、空调、新风、除尘、除湿等诸多设备运行状态变量,进行24小时实时监测与智能化调节…

    2022年7月15日
    11
  • JAVA后端开发浅谈[通俗易懂]

    JAVA后端开发浅谈[通俗易懂]一、背景从后端来讲,目前市场上的电子商务软件基本上可以分为两个阵营,即php阵营和Java阵营。两个阵营的开发基本上都是各自围绕着各自的开发语言(php/Java),选取最为兼容合适的框架结构和数据库,然后进行服务器端的开发。以下附上PHP和Java语言的区别介绍和原文链接:《php和java的区别有哪些》php中文网Java语言Java是一门计算机编程语言,和C++、Python等编程…

    2022年7月8日
    27
  • 异步fifo的工作原理(netty异步方法)

    FPGA(一):异步FIFO实现(包含源码和仿真文件)一、异步FIFO的重要参数及其作用1、FIFO:FirstInputFirstOutput,即先入先出队列,本质是RAM。FIFO有几个最重要的参数:2、wr_clk:写时钟,所有与写有关的操作都是基于写时钟;3、rd_clk:读时钟,所有与读有关的操作都是基于读时钟;4、FIFO_WIDTH:FIFO的位宽,即FIFO中每个地址对应的数据的位宽;5、FIFO_DEPTH:FIFO的深度,即FIFO中能存入多少个(位宽为FIFO_

    2022年4月13日
    121
  • String、StringBuilder和StringBuffer

    String、StringBuilder和StringBuffer这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。首先说运行速度,或者说是执行速度,在这方面运行速度快慢为:StringBuilder > StringBuffer > String  String最慢的原因:  String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但…

    2022年6月13日
    26
  • Linux history命令

    Linux history命令1、在脚本中由于是在另外一个shell中进行语句的执行,所以history显示的是脚本运行的shell的history语句,而不会显示你执行该脚本的终端中的history2、我们可以在家目录下的.bash_history文件中查看自己的历史命令,而history查看的是内存中的历史命令,如果需要将内存中的历史命令加入其中,那么就需要使用history-w将当前终端的历史命令覆盖.bash_history的内容或是history-a在.bash_history文件的尾部添加当前shell的历史命令

    2022年7月13日
    18

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号