C语言自定义类型——联合体、枚举

news2024/11/19 10:48:08

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、联合体
    • (一)、联合体的声明
    • (二)、联合体的特点
    • (三)、联合体大小的计算!!
    • (四)、联合体的小应用
  • 二、枚举
    • (一)、枚举的类型声明
    • (二)、枚举的类型优点
    • (三)、枚举类型的使用
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:


提示:以下是本篇文章正文内容,下面案例可供参考
本文主要介绍了C语言中自定义模型的剩下两种类型——联合体和枚举。

一、联合体

(一)、联合体的声明

  • 联合体的关键字为union,它的声明跟结构体类型,联合体也是由一个或者多个成员构成,这些成员可以选择不同的类型。但是编译器只为最大的成员分配足够的空间。因为联合体所有的成员共用一块内存空间,所有联合体也叫做:共用体
  • 下面是联合体的一段声明和定义变量的代码:
#include<stdio.h>
union Un
{
char c;
int i;
};
int main()
{
//联合体变量的定义,并初始化
union Un un={0};

}

(二)、联合体的特点

  • 联合体最大的特点就是联合体的成员共用一块内存空间,这样一个联合变量的大小,至少是最大成员的大小(因为联合体至少得有能力保存最大的那个成员)
    以代码来验证咱们上面的观点:
#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;
}

运行结果如下:
在这里插入图片描述
从上面运行结果我们可以看出:联合体的成员确实共用一块内存空间,因为它们的起始地址都是一样的。

  • 我们给联合体其中一个成员赋值,其他成员的值也跟着变化。

#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);
}

运行结果如下:
在这里插入图片描述
我们可以看出我们通过改变结构体成员c的值间接性改变了成员i的值(从原来的0x11223344->0x11223355)

(三)、联合体大小的计算!!

  • 要计算联合体的大小我们要了解以下两条规则:
    联合体的大小至少是最大成员的大小;
    当最大成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍;
  • 我们分析一下下面代码中联合体的大小:
#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;
 }

运行结果如下:
在这里插入图片描述
我们从上面特点知道,联合体的大小至少是最大成员的大小,且必须是成员最大对齐数的整数倍。对于结构体Un1来说,最大成员为c,它的大小是5个字节,而最大对齐数是i的对齐数为4,故而应为4的倍数,所以我们应该浪费3个字节,最终Un1结构体的大小为8个字节;对于结构体Un2来说,最大成员为c,它的大小为14个字节,而最大对齐数是i的对齐数为4,故而应为4的倍数,所以我们应该浪费2个字节,最终Un2结构体的大小为8个字节。

(四)、联合体的小应用

  • 使用联合体可以节省空间:
    咱们以下面一个例子来说明:
    比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。
    每种商品都有:库存量、价格、商品类型和商品类型相关的其他信息;例如图书还有的属性:书名、作者、页数;杯子还有的属性:设计;衬衫还有的属性:设计、可选颜色、可选尺寸。
    如果我们不考虑很多的话,可以直接粗暴地定义结构体直接将所有属性囊括即可:
struct gift_list
{
//公共地属性
int stock_number;//库存量
double price;//定价
int item_type;//商品类型

//特殊属性:
char title[20];//书名
char author[20];//作者
int num_pages;//页数


int design[30];//设计
int colors;//颜色
int sizes;//尺寸
}

这样我们所设置地结构体就涵盖了所有属性,要用那块属性地话直接调用即可,但是这样简单粗暴地做法就会使得结构体的大小偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,我们只有部分属性是常用的,有几种属性没有用到
例如对于商品是图书来说的话,design、colors、sizes属性就没有用到。
考虑到这个情况我们可以引进联合体来节省空间,即把公共属性单独列出来,剩余各种商品的本身属性就用联合体给联合起来,(联合体最大的特点是所有成员公用一块内存空间)这样就可以节省内存空间,提高空间利用率
具体实现礼品兑换单的声明如下:

struct gift_list
{
//公共地属性
int stock_number;//库存量
double price;//定价
int item_type;//商品类型

union 
{
struct
{
char title[20];//书名
char author[20];//作者
int num_pages;//页数
}book;//书的特殊属性
struct
{
int design[30];//设计
}mug;//杯子的特殊属性
struct
{
int design[30];//设计
int colors;//颜色
int sizes;//尺寸
}shirt;//衬衫的特殊属性
}item;//特殊属性
};
  • 联合体可以用来判断机器小大端字节序。
    前面我们写的判断大小端字节序的代码为:
#include<stdio.h>
int main()
{
	int a = 1;
	//0x 00 00 00 01
	if (*((char*)&a) == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
}

而我们可以充分利用联合体的内存分配特点,联合体的成员共有一块内存空间,修改代码如下:

#include<stdio.h>
union Un
{
	char c;
	int i;
};
int main()
{
	union Un un = { 0 };
	un.i = 1;
	if (un.c == 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
}


这样会使得代码更加简单好理解,少去了取地址和强转类型的操作。

二、枚举

(一)、枚举的类型声明

  • 我们都知道枚举顾名思义就是一 一地列举,把可能地值一一地给列出来
  • 枚举地关键字是enum,我们以星期天为例来进行枚举地声明
#include<stdio.h>
enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
}D;
int main()
{
	printf("%d\n",Mon);
	printf("%d\n",Tues);
	printf("%d\n",Wed);

}

运行结果如下:
在这里插入图片描述
枚举中成员的取值,默认从1开始,依次递增1,当然也可以手动赋值。
以颜色为例:

#include<stdio.h>
enum
{
RED=2,
GREEN=4,
BLUE=8
};
int main()
{
printf("%d\n",RED);
printf("%d\n",GREEN);
printf("%d\n",BLUE);
}

运行结果如下:
在这里插入图片描述

(二)、枚举的类型优点

我们都知道,定义常量的话可以用#define来实现,那我们用枚举的优点是什么呢?

  • 增加代码的可读性和可维护性
  • 和#define定义的标识符相比较枚举具有类型检查,更加严谨
  • 便于调试,预处理阶段会删除#define定义的符号
  • 使用方便,一次可以定义多个变量
  • 枚举变量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用。

(三)、枚举类型的使用

  • 咱们以构造一个计算器为例来阐述一下枚举的使用
    原先我们设置的计算器为:
void meau()
{
	printf("*****************************\n");
	printf("****1.ADD      2.SUB   ******\n");
	printf("****3.MUL      4.DIV   ******\n");
	printf("****0.Exit             ******\n");
	printf("*****************************\n");
	printf("*****************************\n");

}
int aDD(int x, int y)
{
	return x + y;
}
int sUB(int x, int y)
{
	return x - y;
}
int mUL(int x, int y)
{
	return x * y;
}
int dIV(int x, int y)
{
	return x / y;
}
int main()
{

	int input=0;
	int a = 0, b = 0;

	
	do {
		int result = 0;
		meau();
		printf("请选择->:\n");
		scanf("%d", &input);
		printf("请输入要进行操作的两个数:\n");
		scanf("%d %d", &a, &b);
		switch (input)
		{
		case 1:
			result = aDD(a, b);
			printf("加法的运算结果为:%d\n", result);
			break;

		case 2:
			result = sUB(a, b);
			printf("减法的运算结果为:%d\n", result);
			break;
		case 3:
			result = mUL(a, b);
			printf("乘法的运算结果为:%d\n", result);
			break;

		case 4:
			result = dIV(a, b);
			printf("除法的运算结果为:%d\n", result);
			break;
		case 0:
			printf("退出运算\n");
			exit(-1);
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
	} while(input);
}

我们在switch中还是用数字0,1,2,3,4来做选择,不太直观。
而利用上枚举类型后我们可以修改代码:

#include<stdio.h>
void meau()
{
	printf("*****************************\n");
	printf("****1.ADD      2.SUB   ******\n");
	printf("****3.MUL      4.DIV   ******\n");
	printf("****0.Exit             ******\n");
	printf("*****************************\n");
	printf("*****************************\n");

}
enum Option//更加直观
{
	Exit,
	ADD,
	SUB,
	MUL,
	DIV
};

int aDD(int x, int y)
{
	return x + y;
}
int sUB(int x, int y)
{
	return x - y;
}
int mUL(int x, int y)
{
	return x * y;
}
int dIV(int x, int y)
{
	return x / y;
}
int main()
{

	int input=0;
	int a = 0, b = 0;

	
	do {
		int result = 0;
		meau();
		printf("请选择->:\n");
		scanf("%d", &input);
		printf("请输入要进行操作的两个数:\n");
		scanf("%d %d", &a, &b);
		switch (input)
		{
		case ADD:
			result = aDD(a, b);
			printf("加法的运算结果为:%d\n", result);
			break;

		case SUB:
			result = sUB(a, b);
			printf("减法的运算结果为:%d\n", result);
			break;
		case MUL:
			result = mUL(a, b);
			printf("乘法的运算结果为:%d\n", result);
			break;

		case DIV:
			result = dIV(a, b);
			printf("除法的运算结果为:%d\n", result);
			break;
		case Exit:
			printf("退出运算\n");
			exit(-1);
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
	} while(input);
	



}

运行结果如下:
在这里插入图片描述

我们在代码中充分利用了枚举类型,这样增加代码的可读性与维护性,会让使用者更加直观、清晰明了,这就是枚举的重要使用作用。

总结

本文主要介绍了C语言中自定义类型的剩余两种——联合体和枚举类型,如有错误,请批评指正,感谢支持

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

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

相关文章

在本地运行React集成TypeScript的项目

首先问ChatGPT&#xff0c;贴一段TypeScript代码&#xff0c;问ChatGPT&#xff1a;要运行以上代码&#xff0c;该怎么操作&#xff1f; ChatGPT给出了详细步骤&#xff0c;下面是实际操作&#xff1a; 创建一个react项目&#xff1a; npx create-react-app yuanyu-timeline …

js函数扩展内容---多参数,函数属性,字符串生成函数

1.多参数 在js中&#xff0c;Math.max()方法可以接受任意数量的参数&#xff0c; Math.max(1,2,3,4);//4 Math.max(1,2,3,4,5,6,7,8,9,10)//10 在max方法里面有一个rest参数&#xff0c;它接受了所有参数全部合成到了一个number数组里面&#xff0c; function rest(a,b,...a…

在Linux系统中配置GitHub的SSH公钥

在Linux系统中配置GitHub的SSH公钥&#xff0c;可以让您无需频繁输入密码即可与GitHub仓库进行交互&#xff0c;提高工作效率。以下是配置步骤: 第一步&#xff1a; 检查SSH密钥是否存在 首先&#xff0c;检查您的用户目录下的.ssh文件夹中是否已有SSH密钥。打开终端&#xff0…

openrestry中的hello world

目录 概述实践部署openrestry脚本效果验证 概述 此篇将在 k8s 运行起一个 openrestry   环境&#xff1a;k8s&#xff1a;1.27.9 &#xff0c;openrestry(docker镜像版本)&#xff1a; 1.25.x &#xff0c;k8s 与 ingress 请参考我的其它文章 离线镜像包请参考&#xff1a;op…

Wish卖家必读:如何安全有效地进行店铺测评

Wish以其独特的商业模式和先进的技术在电商领域独树一帜。作为北美和欧洲最大的移动电商平台之一&#xff0c;Wish拥有庞大的用户基础&#xff0c;其中90%的卖家来自中国&#xff0c;这不仅显示了其在全球电商市场中的影响力&#xff0c;也反映了其对中国卖家的吸引力。 Wish平…

微信小程序UGC类功能场景内容安全识别检测实现方案

概念普及 最近开发了一个小程序&#xff0c;属于同城信息发布类的&#xff0c;提交上架的时候&#xff0c;说需要补充社交-笔记类目。 补充完再次提审&#xff0c;又说是项目包含UGC类功能场景。所谓的UGC类功能&#xff0c;就是指用户可以在平台上自由发布信息&#xff0c;这…

创新引领未来,智慧水利在路上:数字孪生技术为水库管理开辟新机遇,带来新挑战,引领水利行业迈向智能化新纪元

目录 前言 一、数字孪生技术概述 二、新机遇&#xff1a;数字孪生技术如何重塑水库管理 1、精准预测&#xff0c;科学调度 2、智能监测&#xff0c;及时预警 3、优化资源配置&#xff0c;提升管理效率 4、促进公众参与&#xff0c;增强透明度 三、新挑战&#xff1a;数字…

【C语言小知识】getchar与putchar

getchar与putchar getchar介绍putchar介绍总结 在学习c语言阶段存在着许多要求输入数值的例子&#xff0c;在输入字符时&#xff0c;如果使用scanf()和printf()根据%c转换说明读写字符&#xff0c;接下来介绍一堆字符输入/输出函数&#xff1a;getchar()和putchar()。 getchar…

nacos源码 nacos注册中心1.4.x 源码 nacos源码如何下载 nacos 客户端源码下载地址 nacos discovery下载地址(一)

首先&#xff0c;发现很多解读文章对核心点讲解的很多&#xff0c;但是我感觉没讲全&#xff0c;记录下&#xff0c;我自己看源码时候一些心得 1. 读源码第一步&#xff0c;先去github, issue, 官网&#xff1a; 1.1 github : https://github.com/alibaba/…

R语言数据分析案例42-基于时间序列模型对股票预测分析和研究

一、研究背景和意义 随着全球经济的不断发展和数字化转型的加速推进&#xff0c;科技公司在全球市场中扮演着日益重要的角色。其中&#xff0c;中国的阿里巴巴集团作为全球最大的电子商务公司之一&#xff0c;其业务范围覆盖电子商务、云计算、金融科技等多个领域。由于其在中…

盘点各个国家的国宝

中国&#xff1a;熊猫 熊猫已有800万年的历史&#xff0c;和它们同时代的动物都已灭绝&#xff0c;大熊猫生存至今成为“活化石”。 俄罗斯&#xff1a;北极熊 北极熊是世界上最大的陆地食肉动物&#xff0c;体型巨大&#xff0c;性格凶猛。 美国&#xff1a;白头海雕 白头海雕…

python基础语法 006 内置函数

1 内置函数 材料参考&#xff1a;内置函数 — Python 3.12.4 文档 Python 解释器内置了很多函数和类型&#xff0c;任何时候都能直接使用 内置函数有无返回值&#xff0c;是python自己定义&#xff0c;不能以偏概全说都有返回值 以下为较为常用的内置函数&#xff0c;欢迎补充…

docker 重要且常用命令大全

本文将总结一些常见的重要的docker命令&#xff0c;以作备忘。后续如果有新的比较常用重要的也会更新进来。欢迎补充。 docker服务管理 首先我们要解释一下&#xff1a;systemctl和docker命令的不同 systemctl&#xff1a;是许多 Linux 发行版中默认的初始化系统和服务管理器。…

transformer初探

transformer初探 self-attentionmultihead-attentionencoderdecoder self-attention 其实就是三个矩阵&#xff0c; W q W_q Wq​、 W k W_k Wk​、 W v W_v Wv​&#xff0c;这三个矩阵就是需要训练的参数。分别得到每个token对应的 q q q k k k v v v&#xff0c;其中 q …

网络安全设备——蜜罐

网络安全设备蜜罐&#xff08;Honeypot&#xff09;是一种主动防御技术&#xff0c;它通过模拟真实网络环境中的易受攻击的目标&#xff0c;以吸引和监测攻击者的活动。具体来说&#xff0c;蜜罐是一种虚拟或实体的计算机系统&#xff0c;它模拟了一个真实的网络系统或应用程序…

【开源项目】LocalSend 局域网文件传输工具

【开源项目】LocalSend 局域网文件传输工具 一个免费、开源、跨平台的局域网传输工具 LocalSend 简介 LocalSend 是一个免费的开源跨平台的应用程序&#xff0c;允许用户在不需要互联网连接的情况下&#xff0c;通过本地网络安全地与附近设备共享文件和消息。 项目地址&…

转盘输入法-单独鼠标版本

序 转盘输入法&#xff0c;给你的聊天加点新意。它不用常见的九宫格或全键盘&#xff0c;而是把字母摆在圆盘上&#xff0c;一滑一滑&#xff0c;字就出来了&#xff0c;新鲜又直接。 单独鼠标版本GIF演示 演示软件下载 转盘输入法https://download.csdn.net/download/u0146…

机器学习原理之 -- XGboost原理详解

XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;是近年来在数据科学和机器学习领域中广受欢迎的集成学习算法。它在多个数据科学竞赛中表现出色&#xff0c;被广泛应用于各种机器学习任务。本文将详细介绍XGBoost的由来、基本原理、算法细节、优缺点及应用场景。 X…

少花点精力找工作,5款AI制作简历工具助你一飞冲天

少花点精力找工作&#xff0c;5款AI制作简历工具助你一飞冲天&#xff01; 01 未来简历&#xff1a;个性化定制&#xff0c;让求职更高效 在求职的海洋中&#xff0c;一份出色的简历是脱颖而出的关键。未来简历&#xff0c;利用GLM-130B大模型&#xff0c;为求职者提供个性化的…

前端面试题18(js字符串特定内容查找方法)

在JavaScript中&#xff0c;有多种方法可以用来查找字符串中的特定内容。以下是一些常用的方法&#xff0c;包括它们的用途和示例代码&#xff1a; 1. indexOf() indexOf() 方法返回指定文本在字符串中第一次出现的索引&#xff08;位置&#xff09;&#xff0c;如果没有找到…