没有联合和枚举 , C语言怎么能在江湖混 ?

2024-02-06 23:52

本文主要是介绍没有联合和枚举 , C语言怎么能在江湖混 ?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本篇会加入个人的所谓‘鱼式疯言’
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
在这里插入图片描述

前言

在本篇文章中,小编将带领友友们体验联合体和枚举的奥妙之处 😎 😎 😎
下面有请我们今天的主角闪亮登场

目录

1.联合体
2.枚举

一. 联合体

<1>. 联合体类型的概念

union union_name {member_type1 member1;member_type2 member2;...
};

union_name 是联合体的名称
member_type1、member_type2 是成员的数据类型
member1、member2 是成员的名称

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

<2>. 联合体的特点

第一个特点:

先请宝子们看一段代码 😃 😃 😃
思考一下哦! ! !

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

在这里插入图片描述
我们发现将i的第4个字节的内容修改为55了

就充分体现了给联合体其中一个成员赋值,其他成员的值也跟着变化的特点。

在这里插入图片描述

鱼式疯言

联合体的主要特点用大白话来说就是:

同空间,互影响,可改变。

<3>.联合体大小

重要的提前说

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

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

证明过程如下

#include <stdio.h>
union Un1
{int i;char c;};
union Un2
{short c[7];int i;
};
int main()
{//下面输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}

在这里插入图片描述

在这里插入图片描述

联合体的大小又谁决定,肯定是由最大的那块数据类型决定,

但我们前提是的至少哦

如果超过了怎么办,我们就必须想结构体一样,利用内存对齐来分配我们的空间大小。

什么! ! !
小爱同学说没有看过我写的结构体内存对齐
那小编就把对应标题链接粘贴在这帮助各位友友一起理解哦 💖 💖 💖
《来 ! 来 ! 来 ! 瞧瞧伏地魔大哥是怎么看C语言结构体的 ! ! !》 http://t.csdnimg.cn/XL9n2

鱼式疯言

最大成员是对齐数的整数倍时,整体就是最大内存

不是的话,就要和结构体对齐一样办,整体内存就是对齐后的内存

是不是有小伙伴就疑惑了,我们结构体和联合体的区别在哪呢 🤔 🤔 🤔

好学的友友们请看下个小标题哦,精彩马上呈现 💖 💖 💖

<4>. 联合体与结构体的对比

#include<stdio.h>
//定义结构体类型
struct S
{char c;int i;
};//定义联合体类型
union Un
{char c;int i;
};int main()
{//计算各种大小printf("%zd\n", sizeof(struct S));printf("%zd\n", sizeof(union Un));return 0;
}

在这里插入图片描述
在这里插入图片描述
有图有真相

鱼式疯言

简而言之,言而简之。

我们的结构体成员不会互相影响,但占内存

我们的联合体会互相影响,但不占内存

<5>. 联合体的实际运用

栗子 一:

使用联合体是可以节省空间的,举例:
比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品:图书、杯子、衬衫。
每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。
图书:书名、作者、页数
杯子:设计
衬衫:设计、可选颜色、可选尺寸
那我们不耐心思考,直接写出一下结构:

//第一种结构体分布
//定义一个结构体礼物
struct gift_list1
{//相同的属性//库存量int nums;//价格float prize;//商品类型char type[20];//书名char bookname[30];//作者char autor[20];//页数int num_book;//设计char dec[50];//颜色char color[20];//大小int sizes;
};

如果我们插入联合体的把不同的结构体属性联合起来就可以节省我们的内存

神奇的代码一:

//第二种插入联合体的结构体分布
//定义一个结构体礼物
struct gift_list2
{//相同的属性//库存量int nums;//价格float prize;//商品类型char type[20];//将不同属性的也联合起来union pu{struct book{//书名char bookname[30];//作者char autor[20];//页数int num_book;};struct cup{//设计char dec[50];};struct shirt{//设计char dec[50];//颜色char color[20];//大小int sizes;};};};

栗子二:

如何判断大小端存储 ? ? ?
假如小爱同学没学联合体之前,肯定会这样写代码
小编说的是假如哦 😁 😁 😁

//判断大小端存储_test
//指针强转法
int conc1(void)
{int a = 1;return *(char*)(&a);
}int main()
{int c1 = conc1();if (c1==1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;
}

在这里插入图片描述
但你今天学了小编写的联合体的介绍,友友们不妨这样写代码吧 💖 💖 💖

//联合体
union MyUnion
{int i;struct MyStruct{char s1;char s2;char s3;char s4;};
};//结构体法
int conc2(void)
{//00 00 00 01 大端存储//01 00 00 00 小端存储union MyUnion a = { 0 };a.i = 1;return a.s1;
}int main()
{int c2 = conc2();if (c2==1){printf("小端存储\n");}else{printf("大端存储\n");}return 0;
}

在这里插入图片描述

在这里插入图片描述
因为 s1 的全部数据 与 i 的前一个字节数据是一致的
所以我们只需要抽离出对应的 s1 即可

鱼式疯言

从中我们看到的联合体本质是联合不同的内存,从中达到节省空间的良效

同时利用公用同一块内存空间的便利,可以有效抽离每个字节的数据

二. 枚举

<1>.枚举的简介

C语言中,枚举是一种用来定义一组具名整数常量的数据类型。枚举类型定义了一系列的枚举常量,也称为 枚举成员。每个枚举常量都有一个对应的整数值,可以在程序中使用这个整数值来表示相应的枚举常量

enum Weekday {MONDAY,    // 0TUESDAY,   // 1WEDNESDAY, // 2THURSDAY,  // 3FRIDAY,    // 4SATURDAY,  // 5SUNDAY     // 6
};

枚举类型的定义使用关键字 “enum”,后面跟着枚举类型的名称,然后是一对花括号 {} ,其中列出枚举常量。每个枚举常量都可以显式地指定一个整数值,如果没有指定,默认从 0 开始递增。

鱼式疯言

从我们的枚举的简介中就可以提炼出很多至关重要的信息

一. 枚举本身是 常量

二. 枚举和结构体,联合体一样都是属于自定义的一种 数据类型

三. 枚举只能常量只能表示的 整数

<2>. 举俩个栗子

栗子 一

//枚举类型的定义
enum MyEnum
{one=1,two,three
};int main()
{int n = 0;scanf("%d", &n);switch (n){case one:printf("one\n");break;case two:printf("two\n");break;	case three:printf("three\n");break;}return 0;
}

在这里插入图片描述
我们可以用这些枚举常量来替换我们case的整数值,以此来增加代码的可读性

鱼式疯言

枚举常量与普通常量之间可以替换

爱提问的小爱同学就要问了,为啥好像用 #define 宏定义枚举常量也是可以的哦 ! ! !
但我们为啥要用枚举呢,这个问题小爱同学问的很好啊。那我们来试试宏定义的效果如何吧 💕 💕 💕

//宏定义的常量
#define one 1
#define two 2
#define three 3int main()
{int n = 0;scanf("%d", &n);switch (n){case one:printf("one\n");break;case two:printf("two\n");break;	case three:printf("three\n");break;}return 0;
}

在这里插入图片描述
哇塞,没想到效果一样嘞 😲 😲 😲
小爱同学又有疑问了 ? ? ?

那居然效果一样,我们是该用 宏定义 还是用 枚举

居然我们有 宏定义 了,为啥还需要 枚举 呢?

是不是 枚举 有比 宏定义 更有优势的地方呢 ?

这些问题呢,我们小编都会 一 一 为宝子们解答哦,先别着急哦 💖 💖 💖
友友们先看第二栗子哦

栗子二(c++的环境测试)

//枚举定义
enum MyEnum
{one,two,three
};int main()
{int n = 0;scanf("%d", &n);enum MyEnum e = 2;switch (n){case one:printf("one\n");break;case two:printf("two\n");break;	case three:printf("three\n");break;}return 0;
}

在这里插入图片描述
友友们是不是想为啥会报错呢? ? ?
这时聪明的小爱同学就大胆的说出了他的想法:
因为这是枚举类型不能匹配整型类型,就会报错 😁 😁 😁
小编不得不为小爱同学点赞哦,完全正确

没错小编提过枚举类型是也是 数据类型 哦,如果出现类型不匹配就很有可能出现 警告和报错

鱼式疯言

无论是什么枚举类型,联合体类型,结构体类型,温馨提示下友友们都记得类型同一哦 ❤️ ❤️ ❤️

<3>. 枚举类型的与宏定义的差别

在上面的中我们可以明显的看到,枚举有类型检查吧,我们宏定义是没有的呢。
所以小编总结了一下五点

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

鱼式疯言

总之枚举的使用可谓是优势俱全啊 💖 💖 💖
但小编的想法是

建议友友们相同类型的常量我们更常用枚举

如果是不同类型的常量我们更常用宏定义来解决呢

总结

在本篇文章中,小编主要带着大家理解了

  • 联合体:熟悉了联合体的定义并知晓了实际的使用场景,还有联合体相比于结构体的优势
  • 枚举:熟悉了枚举如何定义,枚举需要注意的哪些点,以及枚举相比于宏定义的优势

如果觉得小编写的还不错的咱可支持三关下,不妥当的咱评论区指正

希望我的文章能给各位家人们带来哪怕一点点的收获就是 小编创作 的最大动力 💖 💖 💖

在这里插入图片描述

这篇关于没有联合和枚举 , C语言怎么能在江湖混 ?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/685928

相关文章

C语言中%zu的用法解读

《C语言中%zu的用法解读》size_t是无符号整数类型,用于表示对象大小或内存操作结果,%zu是C99标准中专为size_t设计的printf占位符,避免因类型不匹配导致错误,使用%u或%d可能引发... 目录size_t 类型与 %zu 占位符%zu 的用途替代占位符的风险兼容性说明其他相关占位符验证示

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁