C语言 | 自定义类型:联合和枚举

news2024/11/26 12:21:10

目录:

----前言

1. 联合体

  1.1 联合体类型的声明

  1.2 联合体的特点

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

  1.4 联合体大小的计算

  1.5 联合的使用

  1.6联合体的练习

2. 枚举

  2.1 枚举类型的声明

  2.2 枚举类型的优点

  2.3 枚举类型的使用


--前言:

c语言中内置类型,也有自定义的类型。

自定义类型 【结构体--struct,枚举--enum,联合体--union】

上篇文章介绍了结构体类型,这篇介绍剩下两个。

1. 联合体

1.1 联合体类型的声明

像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型。

但是编译器只为最大的成员分配足够的内存空间

联合体的特点是所有成员共用同⼀块内存空间。所以联合体也叫:共用体。

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

#include <stdio.h>
//联合类型的声明
union Un
{
 char c;
 int i;
};

int main()
{
 //联合变量的定义
 union Un un = {0};

 //计算联合变量的⼤小
 printf("%zd\n", sizeof(un));
 return 0;
}

大小为:4

为什么是4呢?

1.2 联合体的特点

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

例如:

//代码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;
}

结果为:

---------代码1输出的三个地址⼀模⼀样

//代码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;
}

结果为:

代码2的输出,我们发现将 i 的第4个字节的内容修改为55了。

我们仔细分析就可以画出,un的内存布局图:

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

我们再对比⼀下相同成员的结构体和联合体的内存布局情况

结构体:

struct S
{
 char c;
 int i;
};
struct S s = {0};

联合体:

union Un
{
 char c;
 int i;
};
union Un un = {0};

1.4 联合体大小的计算

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

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

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

结果为:

对照一下结果,看与自己想的是否一致。

1.5联合体的使用

使用联合体是可以节省空间的,举例:

比如,我们要搞⼀个活动,要上线⼀个礼品兑换单,

礼品兑换单中有三种商品:图书、杯子、衬衫。

每⼀种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、页数

杯子:设计

衬衫:设计、可选颜色、可选尺⼨

如果我们之间给出结果

struct gift_list
{
 //公共属性
 int stock_number;//库存量
 double price; //定价
 int item_type;//商品类型
 
 //特殊属性
 char title[20];//书名
 char author[20];//作者
 int num_pages;//⻚数
 
 char 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
       {
         char design[30];//设计
       }mug;
        struct
      {
        char design[30];//设计
        int colors;//颜⾊
        int sizes;//尺⼨
      }shirt;
       }item;
};

1.6小练习

写⼀个程序,判断当前机器是大端?还是小端?

int check_sys()
{
  union
 {
   int i;
   char c;
 }un;

 un.i = 1;
 return un.c;//返回1是⼩端,返回0是⼤端
}

2. 枚举类型

2.1 枚举类型的声明

枚举顾名思义就是⼀⼀列举。

把可能的取值⼀⼀列举。 比如我们现实生活中:

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

性别有:男、女、保密,

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

三原色,也是可以一一列举

enum Sex//性别
{
 MALE,
 FEMALE, //注意符号
 SECRET
};
enum Color//颜⾊
{
 RED,
 GREEN,
 BLUE
};

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

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

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

例如:

2.2 枚举类型的优点

为什么使用枚举?

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

-----枚举的优点:

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

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

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

4. 使用方便,⼀次可以定义多个常量

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

2.3 枚举类型的使用

enum Color//颜⾊
{
 RED=1,
 GREEN=2,
 BLUE=4
};
enum Color clr = GREEN;
//使⽤枚举常量给枚举变量赋值

那是否可以拿整数给枚举变量赋值呢?

在C语⾔中是可以的,但是在C++是不行的,C++的类型检查比较严格。

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

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

相关文章

String类的几个常用方法

描述 以下程序演示了String类的几个常用方法&#xff0c;包括比较字符串、取得字符串长度、拆分字符串、获取子串、字符串转换成字符数组、获取字符串位置、替换字符串等方法。 案例 public class StringTest {public static void main(String[] args) {//比较字符串String …

阿赵UE学习笔记——28、粒子系统Niagara简介

阿赵UE学习笔记目录 大家好&#xff0c;我是阿赵。   继续学习虚幻引擎的使用。这次开始学习粒子系统的使用。 一、Cascade系统 在介绍UE5的Niagara系统之前&#xff0c;必须先介绍一下旧版本的粒子系统。   在UE4的时候&#xff0c;虚幻引擎的粒子系统叫做Cascade&#x…

ubuntu 使用conda 创建虚拟环境总是报HTTP错误,转换多个镜像源之后仍报错

最近在使用Ubuntu conda创建虚拟环境时&#xff0c;总是报Http错误&#xff0c;如下图所示&#xff1a; 开始&#xff0c;我以为是conda 镜像源的问题&#xff0c;但是尝试了好几个镜像源都不行&#xff0c;还是报各种各样的HTTP错误。后来查阅很多&#xff0c;总算解决了。解…

数学建模--深入剖析线性规划(模型全方位解读+代码分析)

1.简介 &#xff08;1&#xff09;线性规划三要素 &#xff08;2&#xff09;模型适用赛题 2.典例讲解 &#xff08;1&#xff09;问题分析 目标函数是净收益尽可能大&#xff0c;风险尽可能小&#xff1b; 约束条件是交易费的分段函数&#xff0c;以及每一笔投资都是非负数&am…

【精读文献】Scientific data|2017-2021年中国10米玉米农田变化制图

论文名称&#xff1a;Mapping annual 10-m maize cropland changes in China during 2017–2021 第一作者及通讯作者&#xff1a;Xingang Li, Ying Qu 第一作者单位及通讯作者单位&#xff1a;北京师范大学地理学部 文章发表期刊&#xff1a;《Scientific data》&#xff08…

hot100 -- 链表(中)

不要觉得力扣核心代码模式麻烦&#xff0c;它确实比不上ACM模式舒服&#xff0c;可以自己处理输入输出 只是你对 链表 和 return 的理解不到位 &#x1f442; ▶ 屿前世 (163.com) &#x1f442; ▶ see you tomorrow (163.com) 目录 &#x1f382;两数相加 &#x1f6a9;删…

android不同版本(支持>10)获取当前连接的wifi名称

1、AndroidManifest.xml 配置权限 <uses-permission android:name"android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name"android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name&q…

Rust腐蚀服务器清档多教程

Rust腐蚀服务器清档多教程 大家好我是艾西&#xff0c;一个做服务器租用的网络架构师。上期教了大家怎么搭建服务器以及安装插件等那么随着大家自己架设服或是玩耍的时间肯定会有小伙伴想要去新增开区数量或是把原本的服务器进行一些调整等&#xff0c;那么今天主要聊的就是怎…

Cohere Command R+:企业级可扩展大模型

Command R 是一种最先进的 RAG 优化模型&#xff0c;旨在处理企业级工作负载&#xff0c;并首先在 Microsoft Azure 上提供 今天&#xff0c;我们推出了 Command R&#xff0c;这是我们最强大、可扩展的大型语言模型 &#xff08;LLM&#xff09;&#xff0c;专为在实际企业用…

tailwindcss在manoca在线编辑智能感知

推荐一下monaco-tailwindcss库&#xff0c;它实现在monaco-editor网页在线编辑器中对tailwindcss的智能感知提示&#xff0c;在利用tailwindcss实现html效果布局。非常的方便。 生成CSS

Maven POM元素解析(二)

一、parent <parent>元素包含定位此项目将从中继承的父项目所需的信息。注意&#xff1a;此元素的子元素不是插值的&#xff0c;必须作为文字值给定。 ElementTypeDescriptiongroupIdString要从中继承的父项目的组id。artifactIdString要从中继承的父项目的项目id。ver…

python零基础入门笔记【源源老师】

1. print() 输出 &#xff08;1&#xff09;认识英文单词 print: 输出&#xff08;2&#xff09;print() 的作用 print()&#xff1a;用于在控制台上输出你想要的内容。 &#xff08;3&#xff09;代码演示 举例1&#xff1a; 【注意&#xff1a;】用双引号包裹的&#xff0…

java创建线程池的方法

简介 线程池是一种用于管理和重用线程的机制&#xff0c;它可以有效地管理线程的创建和销毁&#xff0c;减少线程创建和销毁的开销&#xff0c;并且能够控制并发线程数量&#xff0c;避免资源耗尽和系统过载。Java 提供了java.util.concurrent 包来支持线程池的实现。 1.Threa…

java(网络编程)

什么是网络编程? 在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行的数据传输。 应用场景&#xff1a;即时通信、网游对战、金融证券、国际贸易、邮件、等等 不管是什么场景&#xff0c;都是计算机跟计算机之间通过网络进行数据传输 Java中可以使用ja…

Qt | 事件第二节

Qt | 事件第一节书接上回 四、事件的接受和忽略 1、事件可以被接受或忽略,被接受的事件不会再传递给其他对象,被忽略的事件会被传递给其他对象处理,或者该事件被丢弃(即没有对象处理该事件) 2、使用 QEvent::accept()函数表示接受一个事件,使用 QEvent::ignore()函数表示…

fork()的一道面试题

前言&#xff1a;题源 #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/wait.h> int main(void) {int i;for(i0; i<2; i){fork();printf("-");}wait(NULL);wait(NULL);return 0; }知道一点fork()这个系统…

移动硬盘盒支持PD充电:优势解析与实际应用探讨

随着科技的飞速发展&#xff0c;数据存储和传输的需求日益增长&#xff0c;移动硬盘盒作为便携式存储设备的重要载体&#xff0c;其功能和性能也在不断提升。近年来&#xff0c;越来越多的移动硬盘盒开始支持PD&#xff08;Power Delivery&#xff09;充电技术&#xff0c;这一…

【云计算】云数据中心网络(四):IPv6 网关

云数据中心网络&#xff08;四&#xff09;&#xff1a;IPv6 网关 1.什么是 IPv6 网关2.IPv6 网关设计思路3.IPv6 网关的主要应用场景3.1 IPv6 私网通信3.2 IPv6 互联网通信3.3 IPv6 互联网通信&#xff08;仅主动访问&#xff09; 1.什么是 IPv6 网关 2017 年&#xff0c;中国…

WordPress 多站点切换域名完整指南:详细步骤和注意事项

因为公司的需要&#xff0c;需要对 WordPress 多站点进行域名切换, 一开始我也找了相关的方案和教程&#xff0c;但是很可惜&#xff0c;国内这一块网上的资料几乎为0&#xff0c;所以我把实现的过程写了一篇文章分享出来&#xff0c;为后来的人铺路。 开始之前&#xff0c;先…

Linux三剑客之awk篇

目录 1、awk 1.1、awk参数 1.2、awk变量 1.3、awk分割符 1.3.1、FS 1.3.2、OFS 1.3.3、RS 1.3.4、ORS 1.3.5、NF 1.3.6、NR 1.3.7、FNR 1.3.8、FILENAME 1.3.9、ARGC与ARGV 1.4、自定义变量 1.5、printf格式化输出 1、awk 作用&#xff1a;具有强大的文本格式化…