【C语言】结构体,联合体,枚举--->自定义类型详解!

 🔥博客主页🔥:【 坊钰_CSDN博客 】

欢迎各位点赞👍评论✍收藏⭐

目录

1. 结构体

1.1 结构体定义

1.2 结构体的声明

1.3 结构体变量的定义和初始化

1.4 结构体的特殊声明->匿名声明

1.5 结构体的自应用

2. 结构体内存对齐

2.1 结构体内存对齐规则

 2.1.1 偏移量

2.2 为什么存在内存对齐

2.3 自定义修改对齐数

3. 结构体传参

4. 联合体

4.1 联合体类型的声明

4.2 联合体的特点

4.3 相同成员变量结构体和联合体比较

4.4 联合体大小的计算

4.5 联合体判断大小端

5. 枚举

5.1 枚举类型的声明

5.2 枚举的优点

5.3 枚举的使用

6. 小结


1. 结构体

1.1 结构体定义

结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,如:

标量、数组、指针,甚⾄是其他结构体

1.2 结构体的声明

struct tag
{
 member-list;
}variable-list;

例:描述一个学生

struct Stu
{
 char name[20];   //名字 
 int age;         //年龄 
 char sex[5];     //性别 
char id[20];      //学号 
}; 

1.3 结构体变量的定义和初始化

//代码1:变量的定义 
struct Point
{
 int x;
 int y;
}p1; //声明类型的同时定义变量p1 
struct Point p2; //定义结构体变量p2 


//代码2:初始化。 
struct Point p3 = {10, 20};
struct Stu //类型声明
{
 char name[15];//名字 
 int age; //年龄 
};
struct Stu s1 = {"zhangsan", 20};//初始化 
struct Stu s2 = {.age=20, .name="lisi"};//指定顺序初始化 


//代码3 
struct Node
{
 int data;
 struct Point p;
 struct Node* next; 
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化 
struct Node n2 = {20, {5, 6}, NULL};//结构体嵌套初始化

1.4 结构体的特殊声明->匿名声明

在声明结构的时候,可以不完全的声明

//匿名结构体类型 
struct
{
 int a;
 char b;
 float c;
}x;


struct
{
 int a;
 char b;
 float c;
}a[20], *p;

两个结构在声明的时候省略掉了结构体标签(tag);

但是要注意

对于上面两个,下面代码是不合法的

p = &x

因为: 

  1. 编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的
  2. 匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次

1.5 结构体的自应用

在结构中包含⼀个类型为该结构本⾝的成员是否可以呢?

例:

struct Node
{
 int data;
 struct Node next;
};

仔细分析,其实是不⾏的,因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的大小【sizeof(struct Node)】就会⽆穷的⼤,是不合理的;

正确的方式:

struct Node
{
int data;
 struct Node* next;
};

应采用结构体指针的方法来自应用;

2. 结构体内存对齐

我们已经掌握了结构体的基本使用了

现在我们深⼊讨论⼀个问题:计算结构体的大小

这也是⼀个特别热门的考点:【 结构体内存对齐

2.1 结构体内存对齐规则

计算时我们要掌握规则

 2.1.1 偏移量

练习:

//练习1 
struct S1
{
 char c1;
 int i;
 char c2;
};
printf("%d\n", sizeof(struct S1));

//练习2 
struct S2
{
 char c1;
 char c2;
 int i;
};
printf("%d\n", sizeof(struct S2));

//练习3 
struct S3
{
 double d;
 char c;
 int i;
};
printf("%d\n", sizeof(struct S3));

//练习4-结构体嵌套问题 
struct S4
{
 char c1;
 struct S3 s3;
 double d;
};
printf("%d\n", sizeof(struct S4));

 结果:

//练习1
---->    12字节

//练习2

---->    8字节
//练习3

---->    16字节

//练习4
---->    32字节

2.2 为什么存在内存对齐

1. 平台不同情况:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定 类型的数据,否则抛出硬件异常

2. 电脑性能:数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要 作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地 址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以 ⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两 个8字节内存块中

 总归一点:用空间来换取时间

那如何做到节省空间?我们可以这样写:

让占用空间小的成员尽量集中在⼀起

struct S1
{
 char c1;
 int i;
 char c2;
};


struct S2
{
 char c1;
 char c2;
 int i;
};

S1 和 S2 类型的成员⼀模⼀样,但是 S1 和 S2 所占空间的大小有了⼀些区别

2.3 自定义修改对齐数

【#pragma】 这个预处理指令,可以改变编译器的默认对⻬数

#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1 

struct S
{
 char c1;
 int i;
 char c2;
};

#pragma pack()//取消设置的对⻬数,还原为默认 

结果:

6字节

结构体在对齐方式不合适的时候,我们可以自己更改默认对齐数

3. 结构体传参

struct S
{
 int data[1000];
 int num;
};

struct S s = {{1,2,3,4}, 1000};


//结构体传参 
void print1(struct S s)
{
 printf("%d\n", s.num);
}


//结构体地址传参 
void print2(struct S* ps)
{
 printf("%d\n", ps->num);
}


int main()
{
 print1(s); //传结构体 
 print2(&s); //传地址 
 return 0;
}

上述函数print2更好,因为:

  1. 函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销
  2. 如果传递⼀个结构体对象的时候,结构体过⼤,参数压栈的的系统开销⽐较⼤,所以会导致性能的下降

总结结构体传参的时候,要传结构体的地址

4. 联合体

4.1 联合体类型的声明

  • 像结构体⼀样,联合体也是由⼀个或者多个成员构成,这些成员可以不同的类型
  • 但是编译器只为最⼤的成员分配⾜够的内存空间
  • 联合体的特点是所有成员共⽤同⼀块内存空间
  • 所以联合体也叫:【共⽤体】
  • 给联合体其中⼀个成员赋值,其他成员的值也跟着变化
#include <stdio.h>

//联合类型的声明 
union Un
{
 char c;
 int i;
};


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

 //计算连个变量的⼤⼩ 
 printf("%d\n", sizeof(un));
 return 0;
}

 结果:

4字节

为什么?

4.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;
}

结果:

 三个地址⼀模⼀样,就说明了联合体共用一个空间;

4.3 相同成员变量结构体和联合体比较

//代码1

struct S
{
 char c;
 int i;
};

struct S s = {0};

//代码2

union Un
{
 char c;
 int i;
};

union Un un = {0};

 它们在内存中储存:

4.4 联合体大小的计算

  • 联合的大小⾄少是最⼤成员的大小
  • 当最⼤成员大小不是最⼤对齐数的整数倍的时候,就要对齐到最⼤对齐数的整数倍 

 计算下面两个联合体大小?

//代码1

union Un1
{
 char c[5];
 int i;
};

//代码2

union Un2
{
 short c[7];
 int i;
};

结果:

//代码1
---->     8字节

//代码2
---->     16字节

4.5 联合体判断大小端

int check_sys()

{
 union
 {
 int i;
 char c;
 }un;

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

5. 枚举

5.1 枚举类型的声明

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

把可能的取值⼀⼀列举

⽐如我们现实⽣活中:

  • 三月有多少天------可一一列举
  • 一个星期有多少天------可一一列举
  • ....
enum Day//星期
{
 Mon,
 Tues,       //记住是逗号
 Wed,
 Thur,
 Fri,
 Sat,
 Sun
};

 以上定义的 【enum Day 】是枚举类型

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

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

enum Day//星期
{
 Mon=2,
 Tues=4,       //记住是逗号
 Wed=6,
 Thur,
 Fri,
 Sat,
 Sun
};

5.2 枚举的优点

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

5.3 枚举的使用

光的三原色:红 绿 蓝 

enum Color//颜⾊
{
 RED=1,
 GREEN=2,
 BLUE=4
};

enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值

6. 小结

以上就是关于自定义类型的内容了,具体还需宝子们去实践,如果觉得该博客对你有用的话,希望一键三连,点个关注不迷路,谢谢支持! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

上海·得物技术沙龙-「无线技术」专场报名开启!

本次无线沙龙聚焦于最新的技术趋势和实践&#xff0c;将在上海/线上为你带来四个令人期待的演讲话题&#xff0c;包括&#xff1a;《快手主App启动接口带宽优化实践》、《得物App视频体验优化实践》、《Chromium内核架构和网络库优化介绍》、《得物App发热监控实践》。相信这些…

本地部署Llama3教程,断网也能用啦!

4月18日&#xff0c;Meta在官方博客官宣了Llama3&#xff0c;标志着人工智能领域迈向了一个重要的飞跃。经过笔者的个人体验&#xff0c;Llama3 8B效果已经超越GPT-3.5&#xff0c;最为重要的是&#xff0c;Llama3是开源的&#xff0c;我们可以自己部署&#xff01; 本文和大家…

C++感受9-Hello Object 生死版•上

你好对象&#xff01; 认识C中基础中的基础类型&#xff1b;创建用户自定义的复合类型&#xff1b;创建新类型的对象&#xff1b;定制新类型对象的生死过程 零、面向对象启蒙 之前我们一直在问候世界&#xff0c;从这节课开始&#xff0c;我们的问候对象就是“对象&#xff08…

验证 python解释器是否安装成功

一. 简介 前一篇文章学习了下载并安装 python解释器&#xff0c;文章如下&#xff1a; windows系统下python解释器安装-CSDN博客 本文验证 python解释器是否安装成功。 二. 验证 python解释器是否安装成功 1. 首先&#xff0c;打开 Windows系统的 "cmd" 界面。…

Netty学习——实战篇8 Handler链调用、TCP粘包和拆包

1 Handler链调用-需求 使用自定义的编码器和解码器来说明Netty的Handler调用机制。客户端发送long类型数据到服务端&#xff1b;服务端发送long到客户端。 2 Handler链调用-实战 2.1 NettyServer.java public class NettyServer {public static void main(String[] args) {…

C语言——小知识和小细节16

一、左旋字符串 例如字符串 abcd &#xff0c;左旋一个就是 bcda &#xff0c;左旋两个就是 cdab 。 方法一&#xff1a;循环 #include <stdio.h> #include <string.h>void func(char* str, int n) {int i 0;int j 0;int len (int)strlen(str);n % len;//超出…

算法打卡day48|动态规划篇16| Leetcode 583. 两个字符串的删除操作、72. 编辑距离

算法题 Leetcode 583. 两个字符串的删除操作 题目链接:583. 两个字符串的删除操作 大佬视频讲解&#xff1a;583. 两个字符串的删除操作视频讲解 个人思路 本题和115.不同的子序列相比&#xff0c;变为了两个字符串都可以删除&#xff0c;整体思路是不变的&#xff0c;依旧…

vue 表格获取当前行索引,加颜色

vue 表格获取当前行索引&#xff0c;加颜色 <span styledisplay:inline-block;width:10px;height:10px;border-radius:50% :style"{background:color[scope.$index]}" />//定义颜色color: [#5387F7, #A794E0, #F3543C, #999999, #77D3F8, #FFA1B4, #26CEBA, #…

ElementUI RUOYI 深色适配

1. 切换按钮&#xff1a;随便找个页面放上去 页面触发逻辑如下 a. html 按钮结构&#xff08;可自定义&#xff09; <el-switchstyle"margin-top: 4px; margin-left: 8px; margin-right: 8px"v-model"isDark"inline-promptactive-icon"Moon"…

使用 Gradio 的“热重载”模式快速开发 AI 应用

在这篇文章中&#xff0c;我将展示如何利用 Gradio 的热重载模式快速构建一个功能齐全的 AI 应用。但在进入正题之前&#xff0c;让我们先了解一下什么是重载模式以及 Gradio 为什么要采用自定义的自动重载逻辑。如果你已熟悉 Gradio 并急于开始构建&#xff0c;请直接跳转到第…

vite和webpacke的常规配置

文章目录 1、vite和webpacke的区分2、vite的常规配置介绍主要部分介绍vite基本配置示例 3、webpacke的常规配置介绍主要部分介绍Webpack 基本配置示例 1、vite和webpacke的区分 相同点&#xff1a; 都是构建工具&#xff0c;用于资源打包 &#xff1b; 都有应用到摇树原理 tre…

网络研讨会 | 数据中心中的人工智能

人工智能&#xff08;AI&#xff09;是嵌入式开发人员必须解决的最复杂的技术之一。将其集成到您的系统中会带来很多问题而不是很多答案。行业媒体Embedded Computing Design特地推出“工程师的人工智能集成指南”月度网络研讨会系列&#xff0c;目的是尽可能地简化嵌入式计算设…

「共沐书香 分享喜“阅”」世界读书日交流活动在国际数字影像产业园圆满举行

人间最美四月天&#xff0c;正是读书好时节。4月23日&#xff0c;在数媒大厦的春日里&#xff0c;我们共同迎来了第29个“世界读书日"。由数字影像联合工会委员会、树莓科技&#xff08;成都&#xff09;集团有限公司工会委员会主办&#xff0c;成都树莓信息技术有限公司、…

Linux(韦东山)

linux和windows的差别 推荐学习路线 先学习 应用程序 然后&#xff1a; 驱动程序基础 最后&#xff1a;项目 韦东山课程学习顺序 看完第六篇之后&#xff0c;还可以继续做更多的官网的项目 入门之后&#xff0c;根据自己的需要学习bootloader / 驱动大全 / LVGL

误差的一阶和二阶——MSE/MAE

variance和bias MSE之前&#xff0c;先看两个更为朴素的指标&#xff1a;variance和bias。 在打靶中&#xff0c;有的人所有的子弹都离靶心很远&#xff0c;偏差显然过高&#xff0c;但是很稳定地维持在某一点附近&#xff1b;有的人平均环数更高&#xff0c;但是分布太过分散…

网络安全之SQL注入漏洞复现(中篇)(技术进阶)

目录 一&#xff0c;报错注入 二&#xff0c;布尔盲注 三&#xff0c;sleep延时盲注 四&#xff0c;DNSlogs 盲注 五&#xff0c;二次注入 六&#xff0c;堆叠注入 总结 一&#xff0c;报错注入 报错注入就是在错误信息中执行 sql 语句&#xff0c;利用网站的报错信息来带…

2024-04-23 linux 查看内存占用情况的命令free -h和cat /proc/meminfo

一、要查看 Linux 系统中的内存占用大小&#xff0c;可以使用 free 命令或者 top 命令。下面是这两个命令的简要说明&#xff1a; 使用 free 命令&#xff1a; free -h这将显示系统当前的内存使用情况&#xff0c;包括总内存、已用内存、空闲内存以及缓冲区和缓存的使用情况。…

使用 Flutter 打造引人入胜的休闲游戏体验

作者 / Zoey Fan 去年&#xff0c;Flutter 休闲游戏工具包进行了一次重大更新。近期在旧金山举办的游戏开发者大会 (GDC) 上&#xff0c;Flutter 首次亮相。GDC 是游戏行业的顶级专业盛会&#xff0c;致力于帮助游戏开发者不断提升开发技能。欢迎您继续阅读&#xff0c;了解开发…

小程序AI智能名片商城系统如何依赖CPM、CPC、CPS技术应用进行营销

在数字化营销的新纪元中&#xff0c;小程序AI智能名片商城系统以其高效、智能的特性&#xff0c;成为了企业营销的重要工具。而CPM、CPC、CPS这三种技术应用&#xff0c;更是为该系统赋予了强大的营销能力。接下来&#xff0c;我们将通过详细的例子&#xff0c;探讨这些技术是如…

微信小程序webview和小程序通讯

1.背景介绍 1.1需要在小程序嵌入vr页面&#xff0c;同时在vr页面添加操作按钮与小程序进行通信交互 1.2 开发工具&#xff1a;uniapp开发小程序 1.3原型图 功能&#xff1a;.点击体验官带看跳转小程序的体验官带看页面 功能&#xff1a;点击立即咨询唤起小程序弹窗打电话 2.…