C语言联合及枚举

一.联合体

1.联合体类型的声明

像结构体一样,联合体也是由一个或者多个成员构成,这些成员可以不同的类型,但是编译器只为最大的成员分配足够的内存空间。

联合体的特点是所有成员共用同一块内存空间。所以联合体也叫:共用体,给联合体其中一个成员赋值,其他成员的值也跟着变化。

2.创建联合体

创建联合体和创建结构体的方式相同,需要一个联合模板和联合变量。下面是几种定义联合体变量的方法:

方法一:先创建模板,再定义变量

// 创建联合体模板union perdata

union perdata

{

    int Class;

    char Office;

};

// 使用该联合体模板创建两个变量a, b

union perdata a,b;

此处,perdata是联合体名,该名字是由我们任意定的,但是尽量起个有意义的名称。其相当于一个模板,可以使用这个模板去定义变量a、b。定义的时候不要忘了union。

方法二:同时创建模板和变量

// 创建联合体模板union perdata的同时定义两个变量a、b

union perdata

{

    int Class;

    char Office;

}a,b;

这与方法一差不多。

方法三:省略联合体名

union

{

    int Class;

    char Office;

}a,b;

相对于方法一与方法二,此处省略了联合体名。虽然更简洁了,但是因为没有了名字,后面就不能用该联合体定义新的变量。

方法四:使用typedef

// 联合体模板union perdata重新命名为perdata_U

typedef union perdata

{

    int Class;

    char Office;

}perdata_U;

// 使用新名字perdata_U创建两个变量a, b

perdata_U a,b;

此处使用typedef为联合体模板union perdata定义一个别名perdata_U。

3.初始化联合体

联合体的初始化与结构体不同,联合体只能存储一个值。联合体有三种初始化方法:

perdata_U a;

a.Class = 10;

perdata_U b = a; /* 1、把一个联合初始化为另一个同类型的联合; */

perdata_U c = {20}; /* 2、初始化联合的第一个成员; */

perdata_U d = {.Office = 30};   /* 3、根据C99标准,使用指定初始化器。 */

4.联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)。

//代码1

#include <stdio.h>

//联合类型的声明

union Un

{

char c;

int i;

};

int main()

{

//联合变量的定义

union Un un = { 0 };

// 下面输出的结果是一样的:

printf("%p\n", &(un.i));

printf("%p\n", &(un.c));

printf("%p\n", &un);

return 0;

}

//代码2

#include <stdio.h>

//联合类型的声明

union Un

{

char c;

int i;

};

int main()

{

//联合变量的定义

union Un un = { 0 };

un.i = 0x11223344;

un.c = 0x55;

printf("%x\n", un.i);

return 0;

}

输出的结果:0x11223355

5.联合体大小的计算

计算原则:

联合的大小至少是最大成员的大小。

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

#include <stdio.h>

union Un1

{

char c[5];

int i;

};

union Un2

{

short c[7];

int i;

};

int main()

{

//下面输出的结果是什么?

printf("%d\n", sizeof(union Un1));

printf("%d\n", sizeof(union Un2));

return 0;

}

输出结果:8   16

6.相同成员的结构体和联合体对比

对比一下相同成员的结构体和联合体的内存布局情况。

struct S

{

 char c;

 int i;

};

struct S s = {0};

union Un

{

 char c;

 int i;

};

union Un un = {0};

二.枚举类型

1.枚举类型的声明

枚举顾名思义就是一一列举,把可能的取值一一列举。

比如我们现实生活中:

一周的星期一到星期日是有限的7天,可以一一列举

月份有12个月,也可以一一列举

这些数据的表示就可以使用枚举了。

enum Day//星期

{

Mon,

Tues,

Wed,

Thur,

Fri,

Sat,

Sun

};

enum Sex//性别

{

MALE,

FEMALE,

SECRET

};

enum Color//颜色

{

RED,

GREEN,

BLUE

};

以上定义的 enum Day , enum Sex , enum Color 都是枚举类型。

{}中的内容是枚举类型的可能取值,也叫枚举常量。

这些可能取值都是有值的,默认从0开始,依次递增1,当然在声明枚举类型的时候也可以赋初值。

enum Color//颜色

{

 RED=2,

 GREEN=4,

 BLUE=8

};

枚举类型需要先定义后使用,这里的定义是类型的定义,不是枚举变量的定义。

既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。

方法一:枚举类型的定义和变量的声明分开

//先定义类型

enum DAY    //类型名称就是enum DAY

{

      MON=1, TUE, WED, THU, FRI, SAT, SUN

};

//后声明变量

enum DAY yesterday;

enum DAY today;

enum DAY tomorrow; //变量tomorrow的类型为枚举型enum DAY

enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum DAY

方法二:类型定义与变量声明同时进行

enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。

{

    saturday,

    sunday = 0,

    monday,

    tuesday,

    wednesday,

    thursday,

    friday

} workday; //变量workday的类型为枚举型enum DAY

//变量days的类型为枚举型enum week

enum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days;

//定义枚举类型并声明了两个枚举型变量

enum BOOLEAN { false, true } end_flag, match_flag;

第二种方式的变量定义是一次性的,后面要想再定义同类型变量就不行了。

第一种方式更灵活。

方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明

typedef enum workday

{

    saturday,

    sunday = 0,

    monday,

    tuesday,

    wednesday,

    thursday,

    friday

} workday; //此处的workday为枚举型enum workday的别名

//或者

//enum workday中的workday可以省略

typedef enum

{

    saturday,

    sunday = 0,

    monday,

    tuesday,

    wednesday,

    thursday,

    friday

} workday; //此处的workday为枚举型enum workday的别名

//定义变量

//变量today和tomorrow的类型为枚举型workday,也即enum workday

workday today, tomorrow;

注意:

同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。

2.枚举类型的优点

我们可以使用 #define 定义常量,为什么非要使用枚举?

枚举的优点:

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

和#define定义的标识符比较枚举有类型检查,更加严谨。

便于调试,预处理阶段会删除 #define 定义的符号

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

枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用

3.枚举类型的使用

(1)先声明后赋值(常用)

#include<stdio.h>

/* 定义枚举类型 */

enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()

{

    /* 使用基本数据类型声明变量,然后对变量赋值 */

    int x, y, z;

    

    x = 10;

    y = 20;

    z = 30;

    

    /* 使用枚举类型声明变量,再对枚举型变量赋值 */

    enum DAY yesterday, today, tomorrow;

    

    yesterday = MON;

    today     = TUE;

    tomorrow  = WED;

    printf("%d %d %d \n", yesterday, today, tomorrow);

}

就像各种类型都有取值范围一样,枚举变量只能接收枚举类型中定义好的符号值(实质是一个int类型的数据)。

(2)声明的同时赋值

#include <stdio.h>

/* 定义枚举类型 */

enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };

void main()

{

    /* 使用基本数据类型声明变量同时对变量赋初值 */

    int x=10, y=20, z=30;

    /* 使用枚举类型声明变量同时对枚举型变量赋初值 */

    enum DAY yesterday = MON,

             today = TUE,

             tomorrow = WED;

    printf("%d %d %d \n", yesterday, today, tomorrow);

}

(3)类型定义、变量声明和赋值同时进行(不推荐,会引入全局变量)

#include <stdio.h>

/* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */

enum DAY

{

    MON=1,

    TUE,

    WED,

    THU,

    FRI,

    SAT,

    SUN

}

yesterday = MON, today = TUE, tomorrow = WED;

/* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */

int x = 10, y = 20, z = 30;

void main()

{

    printf("%d %d %d \n", x, y, z); //输出:10 20 30

    printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3

}

补充:

对枚举型的变量可以直接赋任意整数值,如果赋值浮点数,也会自动去掉小数部分。

赋整数值时,可直接赋值,因为枚举的本质就是整型(int)数据的集合。

#include <stdio.h>

int main()

{

enum week

{

MON, TUE, WEN

};

enum week oneday = 100;

printf("%d,Hello, World! \n", oneday); //100,Hello, World!

}

其实,更正规的做法是进行显式的强制类型转换:

#include <stdio.h>

int main()

{

enum week

{

MON, TUE, WEN

};

enum week oneday = (enum week)100;

printf("%d,Hello, World! \n", oneday); //100,Hello, World!

}

但是不强制转换也可以,和第一个示例一样,不加的话就是隐式类型转换,不会出错。

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

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

相关文章

AVL树超详解上

前言 学习过了二叉树以及二叉搜索树后&#xff08;不了解二叉搜索树的朋友可以先看看这篇博客&#xff0c;二叉搜索树详解-CSDN博客&#xff09;&#xff0c;我们在一般情况下对于二叉搜索树的插入与查询时间复杂度都是O(lgN)&#xff0c;是十分快的&#xff0c;但是在一些特殊…

多维时序 | Transformer+BiLSTM多变量时间序列预测(Python)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 多维时序 | TransformerBiLSTM多变量时间序列预测&#xff08;Python&#xff09; python代码&#xff0c;pytorch框架 程序设计 完整程序和数据获取方式私信博主回复多维时序 | TransformerBiLSTM多变量时间序列预…

Ubuntu 查询未更新的包 进行手动更新

lsb_release -a 查询ubuntu的版本号&#xff0c;我这边是20.04 apt list --upgradable 查询未更新的包 sudo apt --only-upgrade install php/focal 中间遇到输入选择&#xff0c;输入y即可

linux shell脚本编程(分支语句、循环语句)

一、分支语句 1、语法结构 : if 表达式 then 命令表 fi 如果表达式为真 , 则执行命令表中的命令 ; 否则退出 if 语句 , 即执行 fi 后面的语句。 if 和 fi 是条件语句的语句括号 , 必须成对使用 ;命令表中的命令可以是一条 , 也可以是若干条。 2、语法结构为 : if 表达式 t…

pdf太大了怎么变小 pdf太大了如何变小一点

在数字化时代&#xff0c;pdf文件已成为工作与学习的重要工具。然而&#xff0c;有时我们可能会遇到pdf文件过大的问题&#xff0c;这会导致传输困难或者存储不便。别担心&#xff0c;下面我将为你介绍一些实用的技巧和工具&#xff0c;帮助你轻松减小pdf文件的大小。 方法一、…

java之利用二维数组来计算年利润和每个季度的营业额

public class TwodimensionDemo2 {public static void main(String[] args) {//创建二维数组来存储数据int [][]yearArrArr{{22,66,44},{77,33,88},{25,45,65},{11,66,99}};int yearSum0;//遍历二维数组&#xff0c;得到每一个一维数组并求和for (int i 0; i < yearArrArr.…

Linux fork、进程的退出和等待详解

初识fork函数 它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 #include <unistd.h> pid_t fork(void); 返回值&#xff1a;子进程中返回0&#xff0c;父进程返回子进程id&#xff0c;出错返回-1 最简单的fork使用示例 #include<stdi…

每日一题,力扣leetcode Hot100之11. 盛最多的水

解法一&#xff1a; 双层循环遍历找结果&#xff0c;相当于是一个暴力求解方法&#xff0c;两层嵌套循环的时间复杂度是O(N2&#xff09;&#xff0c;所以有一些样例测试时间超时 class Solution:def maxArea(self, height: List[int]) -> int:max_result0for i in range(…

VMware 安装完,设备管理器中没有虚拟网卡(vmnet0、wmnet1、vmnet8) / 虚拟网络编辑器中没有桥接模式

问题&#xff1a;VMware 安装完&#xff0c;设备管理器中没有虚拟网卡(vmnet0、wmnet1、vmnet8) / 虚拟网络编辑器中没有桥接模式 1、确认 Device Install Service 和 Device Setup Manager 没有被禁用 Device Install Service 和 Device Setup Manager是 Windows 操作系统中…

GraphRAG参数与使用步骤 | 基于GPT-4o-mini实现更便宜的知识图谱RAG

首先给兄弟朋友们展示一下结论&#xff0c;一个文本18万多字&#xff0c;txt文本大小185K&#xff0c;采用GraphRAG,GPT-4o-mini模型&#xff0c;索引耗时差不多5分钟&#xff0c;消耗API价格0.15美元 GraphRAG介绍 GraphRAG是微软最近开源的一款基于知识图谱技术的框架&#…

“论系统安全架构设计及其应用”,写作框架,软考高级论文,系统架构设计师论文

论文真题 随着社会信息化进程的加快&#xff0c;计算机及网络已经被各行各业广泛应用&#xff0c;信息安全问题也变得愈来愈重要。它具有机密性、完整性、可用性、可控性和不可抵赖性等特征。信息系统的安全保障是以风险和策略为基础&#xff0c;在信息系统的整个生命周期中提…

73、Flink 的 DataStream API 生产实践总结

0、汇总 1.可以使用 Maven 命令、CURL 命令、IDEA 手动创建 Flink 项目&#xff1b;2.可以使用 Maven Shade 插件将必需的依赖项打包进应用程序 jar 中&#xff1b;3.应该在 Flink 集群的 lib 文件夹内配置需要的&#xff08;核心&#xff09;依赖项&#xff1b;4.应该将程序中…

【Godot4.2】GodotXML插件 - 解析和生成XML

概述 近期在研究基于Godot的XML和SVG解析&#xff0c;并且在昨天&#xff08;2024年7月20日&#xff09;编写了一个简易的SVG文件解析器。 在群友的提示下&#xff0c;知道早就存在GodotXML这样的解析器。所以今天就来测试使用并准备研究学习源代码了。和以往一样&#xff0c…

GD32 MCU是如何进入中断函数的

用过GD32 MCU的小伙伴们都知道&#xff0c;程序是顺序执行的&#xff0c;但当有中断来的时候程序会跳转到中断函数&#xff0c;执行完中断函数后程序又继续回到原来的位置继续执行&#xff0c;那么你们知道MCU是如何找到中断函数入口的吗&#xff1f; 今天我们就以GD32F303系列…

JavaScript进阶之作用域解构箭头函数

目录 一、作用域1.1 局部作用域1.2 全局作用域1.3 作用域链1.4 垃圾回收机制1.5 闭包1.6 变量提升 二、函数进阶2.1 函数提升2.2 函数参数2.3 箭头函数&#xff08;重要&#xff09; 三、解构赋值3.1 数组解构3.2 对象解构&#xff08;重要重要&#xff09; 一、作用域 1.1 局…

【BUG】已解决:ModuleNotFoundError: No module named‘ pip‘

已解决&#xff1a;ModuleNotFoundError: No module named‘ pip‘ 目录 已解决&#xff1a;ModuleNotFoundError: No module named‘ pip‘ 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰…

SpringCloud--负载均衡

目录 前言 一.负载均衡的引入 1.1问题引入 1.2代码修改实现 二.负载均衡介绍 2.1实现负载均衡 2.2负载均衡策略 2.3LoadBalancer 原理 学习专栏&#xff1a;http://t.csdnimg.cn/tntwg 前言 在前面的Eureka当中&#xff0c;我们虽然实现了从注册中心中获取url&#xf…

桌面小宠物发布一周,第一次以独立开发者的身份赚到了100块

收入数据(AppStore一周收入统计) AppStore付费工具榜第七 应用简介 桌面新宠(NewPet)&#xff0c;是我耗时半年开发的一款桌面宠物。我是被 QQ 宠物影响的那批人&#xff0c;上学时天天给 QQ 宠物喂食&#xff0c;很可惜它现在不在了。所以&#xff0c;我开发的初衷是想要在电…

Mysql-查询

1.基本查询 //查询所有内容 select * from 表名;//查询指定字段 select 字段1&#xff0c;字段2&#xff0c;字段3.....from 表名;//查询时给字段起别名 select 字段1 as 别名1 , 字段2 as 别名2 ... from 表名&#xff1b;//去重查询 select distinct 字段列表 from 表名; …

解决显存不足问题:深度学习中的 Batch Size 调整【模型训练】

解决显存不足问题&#xff1a;深度学习中的 Batch Size 调整 在深度学习训练中&#xff0c;显存不足是一个常见的问题&#xff0c;特别是在笔记本等显存有限的设备上。本文将解释什么是 Batch Size&#xff0c;为什么调整 Batch Size 可以缓解显存不足的问题&#xff0c;以及调…