c语言 自定义类型--枚举 、联合 #枚举类型的定义 #枚举的优点 #枚举的使用 #联合类型的定义 #联合的特点 #联合大小的计算

news2024/11/15 21:27:18

文章目录

前言

一、枚举

(一)、枚举类型的定义 

(二)、枚举的优点

(三)、枚举的使用

二、联合

(一)、联合类型的定义

(二)、联合的特点

(三)、联合大小的计算

总结


前言

路漫漫其修远兮,吾将上下而求索。


 枚举、联合跟结构体很像,想要细致地了解结构的相关知识可以戳此链接:http://t.csdnimg.cn/1mymb

一、枚举

在正文开始之前,我们先从定义下手;怎样理解枚举呢?

枚举,顾名思义,看见枚,我们不难想到一枚一枚的量词,连在一起读枚举就有种一一列举的感觉在里面;

例如:星期可以枚举为:星期一、星期二、星期三、星期四、星期五、星期六、星期天。其中这些别列举出来的便叫作枚举常量

注:这些取值只能是有限的几种且可以被一一列举出来,那么此时便可以将这些数据以枚举的形式列举出来;

枚举关键字:enum 

我是这样理解的: e --> extend 展开 ; num --> number 数字 --> 展开很多数字就是枚举

PS.仅限理解!千万别被带偏了,枚举的英文单词为 enumerate

(一)、枚举类型的定义 

还是以星期为例子,想要枚举出星期的枚举类型该如何写呢?

结果如下:

是不是感觉看着跟结构体类型的声明很像,我们来将二者对比一下;

详见上图可知,枚举类型的声明与结构体类型的声明相似,只不过枚举常量之间用分隔开,并且最后一个枚举常量并不需要 ,  ,而结构体成员之间是用 ; 分隔开来;

枚举常量不需要类型,它们仅仅只是一个字符,写好了之后(枚举类型创建好了之后)便不可以被修改;而结构体成员是具有类型的变量;

  • question1:枚举类型是否和结构体类型一样,倘若仅仅只是声明类型就不会占用内存空间?

枚举类型在声明的时候不会占用内存空间,只有在利用该枚举类型创建枚举变量的时候才会向内存申请空间来存放数据;

枚举常量作为字符都是有值的,默认从0开始,一次递增1;当然在定义的时候可以为其赋上初始值;

从上图可得知,枚举常量是有值的,并且默认第一个枚举常量得值为0,并且随着枚举常量数量得增多,其值依次在上一个枚举常量值的基础上增加1;

当我们为枚举常量赋值时:

我们再给一个枚举变量赋值:

可见,依次在上一个枚举常量值的基础上增加1的属性仍然存在;

注:此处仅仅是为枚举常量赋值,并不是在修改枚举常量;而之所以这些常量不占内存空间,可能是由于编译器将这些常量以符号的形式存在的;但是枚举类型倘若作为代码存在确实是需要空间来存放的,但这个空间并不是在内存中开辟的(况且内存并不是为每一个常量、符号而开辟空间),故而枚举类型的声明并不会占用内存空间;

question 2:是否可以像使用结构体类型那样使用枚举类型?

可以;使用如下图:

利用枚举类型 enum Day 创建了变量date, 枚举变量date 的取值只能是枚举类型中列举出来的值,不能用其他值给类型为 enum Day 的变量赋值!

(二)、枚举的优点

看了上文,你可能会感觉到枚举常量和#define 定义的标识符常量有点相似,只不过枚举可以一次解决多个;

既然相似为什么还存在枚举呢?或者说枚举的优点有哪些?

枚举的有优点:

1、增加代码的可读性和可维护性

2、与#define 定义的标识符常量比起来,枚举具有类型检查,更加严谨

3、防止命名污染(封装)

4、便于调试

5、便于使用,一次可以定义多个常量;

光看上面枚举的优点,可能有点干巴巴的,下文便结合一些例子来理解;

  • 增加代码的可读性与可维护性

在写通讯录的时候,菜单中对应的功能在switch 语句中是用数字来对应的,这是因为case 后面只能接整型常量表达式;而数字对应相应的功能,需要配合菜单一起看才好理解,但是如果使用枚举常量便可以增加代码的可读性,况且在维护上也更利于维护

而如若采用了枚举:

  • 与#define 定义的标识符常量比起来枚举具有类型检查,更加严谨

#define 定义的标识符常量是不具有类型的;而枚举常量是带有类型的;

  • 防止命名污染(封装)
  • 便于调试

#define 定义的标识符常量工作的实质是替换,在调试的过程中就不利于观察细节;

#define 定义的标识符常量在什么时候完成替换的呢?

当你写了一个 .c 文件的时候,此文件是要经过编译、链接,最后生成了 .exe 文件;而在编译的过程中会有一个小过程,叫做预处理正是在预处理阶段,标识符常量便会完成替换

调式是在那个过程呢?

我们调试代码调试的是此代码经过预处理、编译、链接产生的 .exe 文件

但是对于枚举常量来说并不是以替换来实现的,倘若你在代码中使用了枚举常量,在调试的时候仍然可以观察到这些枚举常量的值;故而枚举更便于调试;

  • 使用方便,一次可以定义多个常量;

(三)、枚举的使用

只能拿枚举常量给枚举变量赋值,不然会出现类型的差异;

二、联合

(一)、联合类型的定义

联合体也是一种特殊的结构体类型;

但是此种特殊的结构体类型变量也就是联合变量,包括了一系列的成员,特征是这些成员共用同一块空间

故而联合也称为共用体;

联合的关键字为 union;

联合类型的声明如下:

这么看,联合体类型的声明除了关键字与结构体类型的声明不太一样,表面上都是一样的;那么联合体成员使用内存空间的情况与结构体变量一样吗?

我们可以测试一下:

我们发现,联合体变量其成员使用内存空间的情况与结构体变量成员使用规则有所不同;下图便是对比:

从上图我们可以得知,联合变量的成员会共用内存(但是联合体变量整体占用的内存需要对齐到最大对齐数的整数倍),而结构体成员在使用内存时存在对齐规则

利用代码验证一下来联合成员是否真的会共用同一块内存空间?

综上,联合变量相较于结构体变量存在两点不同(只谈使用不谈作用),

  • 在声明上仅仅只是其关键字不同;
  • 以及二者成员使用内存空间的规则不同,联合体变量的成员会共用空间,而结构体变量的成员遵循对齐规则;

看到这你可能就会有疑问了,联合体变量的成员共用内存空间,其数据不能单独存放,那么联合体变量的使用场景是什么呢?

联合体巧妙的运用场景:(例子如上图)有时候会使用到a 所占用的这块空间,而有时候会使用到 b所占用的空间,即联合体变量的成员不会同时使用;于是乎就在一定程度上较少了对空间的使用节省了空间;

当你想在联合体变量 u中成员 a 中存放数据的时候,那便将 成员a 所占用 的1 byte 的空间给覆盖掉;而当你想在联合体变量 u 中成员 b 中存放数据的时候,那便将成员 b 所占用的 4 byte 的空间给覆盖掉;

(二)、联合的特点

联合体成员是共用一块内存空间的,这样一个联合变量的大小,至少得是最大成员的大小,因为联合体至少得有能力让占用内存空间最大的那个成员能够存放其数据;

调试如下:

从调试的图中,我们可以感知到,联合体成员共用空间的特征;

(三)、联合大小的计算

  • 联合体的大小至少得是其最大成员的大小(请注意“至少”)
  • 当最大成员的大小不是最大对齐数的整数倍的时候,要对齐到最大对齐数的整数倍

图解分析如下:

成员数组 ch 的对齐是按照其中的元素进行对齐的,而VS编译器默认的对齐数为 8 --> 取其较小值,故而成员 ch 的对齐数为 1;而成员 i 的对齐数为 4 ;--> 此联合体变量 u 的最大对齐数为 4,则其大小必须是 4 的整数倍;

注:vs 编译器中默认对齐数为8;

在vs 编译器上对于一个变量对齐数的计算,在此变量自身大小与默认对齐数之间取得较小值,就为此变量的对齐数;

倘若在一个编译器上没有默认对齐数的概念,那么该变量自身的大小便为其对齐数的大小;

question 1:你可能会对上面数组 ch 计算所得的对齐数为1 有所疑惑;

你可能会这样想,数组ch 的类型为 char [6] ,  所占空间的大小为 6byte ,vs 编译器默认的对齐数为 8 --> 取其较小值,则会认为成员 ch 的对齐数为6;

实际上不是这样想的,首先数组是一类元素的集合,元素与元素就是单独的个体,只不过放在一个数组之中,而此处讨论的是数组 ch 在对齐时的对齐数为多少,故而应该看的是数组中元素的大小;

ch 数组元素的大小为 1,vs 编译器默认的对齐数为8 --> 取其较小值:1;故而成员 ch 的对齐数为1 ;

注:不要天真地以为联合体的大小为其最大成员的大小;

再举一个例子,加深对联合大小的计算;

分析:成员ch为一个数组,整个数组的所占内存空间的大小为 14 byte ,其元素为 short 类型的数据,即该数组中元素的大小为 2byte,vs 编译器默认的对齐数为8 --> 成员ch 的对齐数为 2;

成员 i 自身大小为 4byte ,vs 编译器默认的对齐数为 8 --> 成员 i 的对齐数为4 ;

所以联合变量 u 的最大对齐数为 4 ;

图解如下:

  


总结

1、枚举的关键字 : enum ;

在声明的时候,带上标签名、成员列表、变量列表(可省略),但是在成员列表之间与结构体不同的是,枚举的成员为带有值得字符无需带上类型,而结构体成员是需要带上变量类型的;且在枚举成员之间是用 , 隔开,最后一个成员不需要  , ,而结构体的每一个成员后面都需要带上 ;  .

2、枚举的优点:

1、增加代码的可读性和可维护性

2、与#define 定义的标识符常量比起来,枚举具有类型检查,更加严谨

3、防止命名污染(封装)

4、便于调试

5、便于使用,一次可以定义多个常量;

3、联合的关键字: union ;

在声明的时候,需带上标签名、成员列表、变量列表(可省略),联合的成员之间和结构体成员之间一样用 ; 隔开;

但是其成员在内存的分配上不同,联合的成员会共用内存空间,而结构体体成员不会共用内存空间,但是得遵循对齐规则;

联合变量的大小至少是其最大成员的大小,但是并不意味着联合的大小就是其最大成员的大小,因为联合的大小和结构体一样,满足其大小为其最大对齐数的整数倍;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2076617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SpringBoot+Vue+uniapp的“村游网”系统的微信小程序开发的详细设计和实现(源码+lw+部署文档+讲解等)

文章目录 前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus 系统测试系统测试目的系统功能测试系统测试结论 为什么选择我代码参考数据库参考源码获取源码获取 前言 🌞博主介绍 :✌全网粉丝15W,CSDN特邀作者、21…

基于状态机实现WIFI模组物联网

1.0 状态机框架原理 如果成功的话就连接热点,如果失败就返回AT通信检查,如果AT通信检查还是失败就放回硬件复位这个状态,如果热点链接成功,就连接MQTT指令,如果失败就返回AT通信检查,如果成功就连接云平台通…

跟着B站前端面试总结回顾前端基础知识(一)

组件划分标准 组件划分_哔哩哔哩_bilibili 在前端Vue开发中,组件的划分是构建高效、可维护应用的关键步骤。Vue组件的划分标准通常基于多个方面的考虑,包括但不限于功能独立性、复用性、可维护性和可扩展性。以下是一些Vue组件划分的标准: …

破解历史合同“旧题” 答好集体经济“新篇”

——汕头市龙湖区:全面推进乡村振兴战略 实现农村集体经济新飞跃 农村集体资产资源是乡村赖以生存的家底,也是村集体经济发展壮大、更好推动乡村振兴战略加力提速的承载。自2023年10月开始,在汕头市龙湖区的广袤乡村上,一场关于村…

图解搜索算法(BFS、DFS、Dijstra算法、KSP算法、A*算法)

文章目录 深度优先搜索算法广度优先搜索算法Dijkstra算法KSP算法A*算法 由于在工作中用到了BFS算法、DFS算法、Dijkstra算法、KSP算法,因此将上述算法的工作原理记录一下,同时用图解的方式解释相应的算法。A*算法由于本文在工作中,还没用过&a…

深度学习语义分割篇——LR-ASPP原理详解+源码实战

🍊作者简介:秃头小苏,致力于用最通俗的语言描述问题 🍊专栏推荐:深度学习网络原理与实战 🍊近期目标:写好专栏的每一篇文章 🍊支持小苏:点赞👍🏼、…

简单使用富有创造力的DALL·E 3 图像生成器——OpenAI Images Generations API

OpenAI Images Generations API 申请及使用 DALL-E 3 是 OpenAI 开发的两个版本的图像生成模型,它们能够根据文本描述生成高质量的图像。 本文档主要介绍 OpenAI Images Generations API 操作的使用流程,利用它我们可以轻松使用官方 OpenAI DALL-E 的图…

类和构造函数之间的继承

类之间构造函数的继承是面向对象编程中的一个重要概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。通过这种方式,子类可以复用父类的代码,从而避免重复,提高代码的可维护性…

Swagger的增强knife4j

效果图 导入依赖 <!--不是导入swagger原因就是&#xff1a;knife4j对swagger增强--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.2</version><…

考研数学| 张宇线代9讲换李永乐线代讲义,强化来得及吗?

张宇线代9讲&#xff1a; 张宇老师的线代九讲和张宇老师的线代课程搭配使用&#xff0c;相对于更适合线代底子足够强的同学。整体书的题目难度较大&#xff0c;所以开始刷了之后发现不适合自己可以选择换一本习题册&#xff0c;当然如果担心时间不够还是想尽力刷下去的话可以去…

8款每天都能用到的网站和APP,值得收藏

5个网站3个APP&#xff0c;都是自己每天常用的一些工具&#xff0c;强大实用&#xff0c;能给自己省不少事&#xff0c;分享给大家~ 1、奶牛快传 https://cowtransfer.com/ 一个让你轻松上传和分享大文件的网站。跟那些需要下载app、操作复杂的服务不同&#xff0c;奶牛快传…

随机森林与线性回归

集成学习方法之随机森林 集成学习&#xff08;Ensemble Learning&#xff09;是一种通过组合多个分类器来提高预测性能的方法。主要分为三种类型:Bagging、Boosting和Stacking。以下是集成学习的基本步骤和概念&#xff1a; 1数据采样&#xff1a;从训练集中有放回地随机抽取…

前端手写源码系列(一)—— 手写防抖和节流

目录 1.实现防抖函数&#xff08;debounce&#xff09;2.实现节流函数&#xff08;throttle&#xff09;时间戳的方式&#xff1a;定时器方式&#xff1a; 3.总结 1.实现防抖函数&#xff08;debounce&#xff09; 防抖函数原理&#xff1a;把触发非常频繁的事件合并成一次去执…

修复照片,2024年好用的图片修复工具推荐

在日常中&#xff0c;我们总爱用镜头捕捉生活的每一个瞬间&#xff0c;但随着时间的推移&#xff0c;那些珍贵的记忆可能会因像素不高、保存不当等原因变得模糊不堪。这时需要将模糊的照片修复清晰成为我们迫切的需求。下面给大家分享4种2024年好用值得推荐的修复工具&#xff…

【自动化】一共获取6600多公司信息【逆向】一页15还加密。

一、【逆向】一页15还加密。 二、【自动化】一共获取6600多公司信息 三、对于两种方式我喜欢第二种自动化 from DrissionPage import ChromiumPage, ChromiumOptions import time # chrome:version co = ChromiumOptions().set_paths(browser_path=r"C:\Users\lenovo\A…

qt-19 QMainWindow窗口组件-菜单栏-工具栏

QMainWindow窗口组件-菜单栏-工具栏 showwidgetshowwidget.hshowwidget.cpp processorprocessor.hprocessor.cpp main.cpp运行图 showwidget showwidget.h #ifndef SHOWWIDGET_H #define SHOWWIDGET_H#include <QWidget> #include <QLabel> #include <QTextEd…

Sparse Kernel Canonical Correlation Analysis

论文链接&#xff1a;https://arxiv.org/pdf/1701.04207 看这篇论文终于看懂核函数了。。谢谢作者

小乌龟运动控制-2 小乌龟走方形

目录 第一章 小乌龟划圆圈 第二章 小乌龟走方形 文章目录 目录一、简陋版-乌龟行走方形二、强化版-乌龟行走方形 一、简陋版-乌龟行走方形 常见的简陋的控制乌龟行走方形的方式很简单&#xff0c;例如下面&#xff0c;可以测试下&#xff1a; 我们需要创建一个名为draw_squa…

韩顺平Java-第二十六章:正则表达式

一 正则表达式入门 1 极速体验正则表达式威力 package com.hspedu.regexp;import java.util.regex.Matcher; import java.util.regex.Pattern;体验正则表达式的威力&#xff0c;给我们文本处理带来哪些便利public class Regexp_ {public static void main(String[] args) {Str…

每日OJ_牛客_剪花布条(string内置函数)

目录 牛客_剪花布条&#xff08;string内置函数&#xff09; 解析代码 牛客_剪花布条&#xff08;string内置函数&#xff09; 剪花布条__牛客网 解析代码 题意就是在S串中&#xff0c;T串整体出现了多少次。C语言可以通过strstr函数找&#xff0c;用STL的string库可以通过f…