结构体类型详细讲解(附带枚举,联合)
前言:
如果你还对结构体不是很了解,那么本篇文章将会从 为什么存在结构体,结构体的优点,结构体的定义,结构体的使用与结构体的大小依次介绍,同样会附带枚举与联合体
目录
为什么存在结构体:
结构体的优点
结构体的定义
结构体的使用
方法一:
方法二 函数传值打印
方法三 函数传址打印 两种打印方法
第二种是利用-> 这里的 ->就相当于(*).
方法四 跟方法三差不多,不利用函数打印
结构体的typedef
结构体的大小计算
⾸先得掌握结构体的对⻬规则:
1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。VS 中默认的值为 8
Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
先解决对其数问题
枚举
枚举的使用案例
联合体(也叫共用体)
为什么存在结构体:
当一个整体由多个数据构成时,于是人们就创造了数组,我们用数组来表示这个整体,但是数组有个特点:内部的每一个元素都必须是相同类型的数据。 ☀ 在实际应用中,我们通常需要由不同类型的数据来构成一个整体,比如学生这个整体可以由姓名、年龄、身高等数据构成,这些数据都具有不同的类型,姓名可以是字符串类型,年龄可以是整型,身高可以是浮点型。 ☀ 为此,C语言专门提供了一种构造类型来解决上述问题,这就是结构体,它允许内部的元素是不同类型的。
结构体的优点
- 可以在一个结构中声明不同的数据类型。
- 相同结构的结构体变量是可以相互赋值的。
- 结构体的存储方式可以提高CPU对内存的访问速度。
- 结构体可以将同一对象的多个数据类型存储在一起,方便数据的存储和处理。
- 可以通过结构体变量名和成员名来访问数据。
- 可以定义结构体数组,方便批量处理数据。
那么有有优点就会有缺点:
- 如果项目的复杂性增加,管理所有数据成员就变得很困难 。
- 对程序中的一个数据结构进行更改需要在其他几个地方进行更改。 所以很难跟踪所有的变化。
- 结构体需要更多的存储空间,因为它为所有数据成员分配内存,甚至速度更慢。
- 结构体占用更多存储空间,因为它为所有不同的数据成员提供内存,而联合仅占用最大数据大小参数所需的内存大小,并且与其他数据成员共享相同的内存。
结构体的定义
一般结构体定义便是如下
struct stu
{//变量成员
};
这里的struct是必不可少的部分,而stu是我们自拟定的,里面便是填充的变量成员
这个结构体就是struct stu类型的
同理下面这个结构体就是struct st类型的
struct st
{//变量成员
};
这时候我们便可以在里面填充成员
比如这样
struct st
{int a;char b;struct st* ps;//也可以填充这个类型的指针
};
那么结构体定义完后,我们开始讲解怎么去使用
结构体的使用
这里的s为变量名
struct st
{int a;char b;
};
int main()
{struct st s = { 10,'b' };//初始化return 0;
}
接下来介绍打印
方法一:
struct st
{int a;char b;
};
int main()
{struct st s = { 10,'b' };//初始化printf("%d %c", s.a, s.b);return 0;
}
方法二 函数传值打印
struct st
{int a;char b;
};
void print(struct st ps)
{printf("%d %c", ps.a, ps.b);
}
int main()
{struct st s = { 10,'b' };//初始化print(s);return 0;
}
方法三 函数传址打印 两种打印方法
第一种的打印是利用解引用
第二种是利用-> 这里的 ->就相当于(*).
struct st
{int a;char b;
};
void print(struct st* ps)
{printf("%d %c\n", (*ps).a, (*ps).b);printf("%d %c\n", ps->a, ps->b);
}
int main()
{struct st s = { 10,'b' };//初始化print(&s);return 0;
}
方法四 跟方法三差不多,不利用函数打印
struct st
{int a;char b;
};
int main()
{struct st s = { 10,'b' };//初始化struct st* ps = &s;printf("%d %c\n", (*ps).a, (*ps).b);printf("%d %c\n", ps->a, ps->b);return 0;
}
结构体的typedef
当一个结构体类型的类型名过于长的时候,我们不免过于不想去写,这时候就可以用typedef
(重命名)使用起来很简单
typedef struct st
{int a;char b;
}st;
int main()
{struct st s = { 10,'b' };//初始化//等价于st s = { 10,'b' };//return 0;
}
结构体的大小计算
先举例一个代码
代码跑出来这个结构体大小是8
那么怎么计算的呢? 其原理就是对其原则
⾸先得掌握结构体的对⻬规则:
1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。VS 中默认的值为 8
Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
我们计算一下这个结构体大小
struct S1
{char c1;int i;char c2;
};
printf("%d\n", sizeof(struct S1))
先解决对其数问题
char 自身对齐数为1 vs上默认对齐数为8 实际取小的 那么最后为1
int 为4
偏移量
在C语言中,偏移量通常指的是结构体中成员变量相对于结构体起始地址的偏移量。假设有一个结构体定义如下:
struct Person {int id;char name[20];int age;
};
假设struct Person p;
是一个Person
类型的结构体变量,我们可以通过&p.id
、&p.name
和&p.age
来获取各个成员变量的地址。偏移量就是从结构体起始地址到成员变量地址的字节偏移量。
例如,假设&p
表示结构体p
的起始地址,&p.id
表示id
成员变量的地址,那么&p.id - &p
就是id
相对于结构体起始地址的偏移量。在C语言中,可以使用指针和强制类型转换来计算偏移量,例如:
int offset = (char *)&p.name - (char *)&p;
这样就可以得到name成员变量相对于结构体p
的偏移量。偏移量在一些底层编程中经常用来访问结构体中的特定成员变量,尤其是在处理二进制数据或者硬件寄存器时非常有用。
画图表示如下
那么我们进行利用图进行计算
typedef struct st
{char c1;int i;char c2;
}st;
int main()
{printf("%zd", sizeof(st));return 0;
}
第一个char偏移量为0放于第一个,int放于偏移量为4的整数倍数处 ,最后一个char偏移量为1,放于1的整数倍数处,
用图表示如下
图上的大小一共占了9个字节,
然后我们进行最后一步 最大对齐数为4 而9不是最大对齐数的整数倍 所以要浪费3个字节补充该结构体大小到12;
那么最大怎么算了就可以解答上面那个问题为什么是8
//练习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));
答案分别是16 32
枚举
在《C语言深度剖析》这本书中留有一个问题,枚举变量的大小是多少?
大家猜一下大小为多少
enum Color
{GREEN = 1,RED,BLUE,GREEN_RED = 10,GREEN_BLUE,sss,
}c;
int main()
{printf("%zd", sizeof(c));
}
答案是4,为啥呢?
因为,枚举变量的取值为花括号内的任意一个值(有且只能有其中一个值),而这个值是int型的,在X86系统中,int型的数据占内存4个字节。所以sizeof(c) = 4,也就是枚举变量的值为4。
枚举的使用案例
当我们写菜单的时候,会用到switch语句
当我们写case是一般会用到case 1: case 2:
但如果功能一旦多我们就会分不清该case 要实现哪一项功能
这时候就可以用到枚举 就比如通讯录
enum option
{EXIT,//等价于0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW, //5SORT,//6SAVE,//7
};void menu()
{printf("**************************************\n");printf("***** 1.add 2.del *****\n");printf("***** 3.search 4.modify *****\n");printf("***** 5.show 6sort *****\n");printf("***** 7.save 0.exit *****\n");printf("**************************************\n");
}
int main()
{do {menu();printf("请输入你的选择:>");scanf("%d", &input);switch (input){case ADD:Addcontact(&con);break;case DEL:Delcontact(&con);break;case SEARCH:Searchcontact(&con);break;case MODIFY:Modifycontact(&con);break;case SHOW:Showcontact(&con);break;case SORT:SortContact(&con);break;case SAVE:SaveContact(&con);break;case EXIT:SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");break;default:printf("输入错误,请重新输入:>\n");break;}} while (input);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了(其实是改的低地址处的数据)
同样大端下会打印55223344;
利用联合体写一个函数判断机器为大端还是小端
int check_sys()
{union{int i;char c;}un;un.i = 1;return un.c;//返回1是⼩端,返回0是⼤端
}
相关文章:

结构体类型详细讲解(附带枚举,联合)
前言: 如果你还对结构体不是很了解,那么本篇文章将会从 为什么存在结构体,结构体的优点,结构体的定义,结构体的使用与结构体的大小依次介绍,同样会附带枚举与联合体 目录 为什么存在结构体: 结构…...
编程生活day1--个位数统计、考试座位号、A-B、计算阶乘和
个位数统计 题目描述: 定一个 k 位整数 Ndk−110k−1⋯d1101d0 (0≤di≤9, i0,⋯,k−1, dk−1>0),请编写程序统计每种不同的个位数字出现的次数。例如:给定 N100311,则有 2 个 0,3 个 1,和 …...

mysql体系结构及主要文件
目录 1.mysql体系结构 2.数据库与数据库实例 3.物理存储结构编辑 4.mysql主要文件 4.1数据库配置文件 4.2错误日志 4.3表结构定义文件 4.4慢查询日志 4.4.1慢查询相关参数 4.4.2慢查询参数默认值 4.4.3my.cnf中设置慢查询参数 4.4.4slow_query_log参数 4.4.…...

PwnLab靶场PHP伪协议OSCP推荐代码审计命令劫持命令注入
下载链接:PwnLab: init ~ VulnHub 安装: 打开vxbox直接选择导入虚拟电脑即可 正文: 先用nmap扫描靶机ip nmap -sn 192.168.1.1/24 获取到靶机ip后,对靶机的端口进行扫描,并把结果输出到PwnLab文件夹下,命名…...
涉密信息系统集成资质八大类别办理条件是什么?
涉密资质分为八个不同类别,那每个类别的申报条件有哪些?让我们一起来看看吧: 涉密资质申报条件 依据《涉密信息系统集成资质管理办法》的有关规定,申请涉密信息系统集成资质的企事业单位,除符合《涉密信息系统集成资…...
Shell脚本总结-反引号-${}-$()
反引号 反引号的作用就是将输出结果显示出来。 [rootldpbzhaonan bash]$ echo $a ldpbzhaonan${} ${}引用变量,包含自定义的和环境变量。 [rootldpbzhaonan bash]$ a1 [rootldpbzhaonan bash]$ echo ${a} 1$() $()和反引号,返回的是一个指令或者程序…...

Spring MVC入门(4)
请求 获取Cookie/Session 获取Cookie 传统方式: RequestMapping("/m11")public String method11(HttpServletRequest request, HttpServletResponse response) {//获取所有Cookie信息Cookie[] cookies request.getCookies();//打印Cookie信息StringBuilder build…...

RuoYi-Vue-Plus(基础知识点jackson、mybatisplus、redis)
一、JacksonConfig 全局序列化反序列化配置 1.1yml中配置 #时区 spring.jackson.time-zoneGMT8 #日期格式 spring.jackson.date-formatyyyy-MM-dd HH:mm:ss #默认转json的属性,这里设置为非空才转json spring.jackson.default-property-inclusionnon_null #设置属性…...
使用verillog编写KMP字符串匹配算法
设计思路如下: 定义模块的输入输出信号:包括时钟信号clk、复位信号rst、模式串pattern、文本串text以及输出信号match。定义所需寄存器和变量:使用寄存器来存储状态机的状态以及其他控制变量,如模式串数组P、失配函数数组F、模式串位置p_index、文本串位置t_index等。在时钟…...
《每天十分钟》-红宝书第4版-对象、类与面向对象编程(五)
对象迭代 在 JavaScript 有史以来的大部分时间内,迭代对象属性都是一个难题。ECMAScript 2017 新增了两个静态方法,用于将对象内容转换为序列化的——更重要的是可迭代的——格式。这两个静态方法Object.values()和 Object.entries()接收一个对象&#…...

华为ensp中rip动态路由协议原理及配置命令(详解)
CSDN 成就一亿技术人! 作者主页:点击! ENSP专栏:点击! CSDN 成就一亿技术人! ————前言————— RIP(Routing Information Protocol,路由信息协议)是一种距离矢…...

学习要不畏难
我突然发现,畏难心是阻碍我成长的最大敌人。事未难,心先难,心比事都难,是我最大的毛病。然而一念由心生,心不难时,则真难事也不再难。很多那些自认为很难的事,硬着头皮做下来的时候,…...

mysql迁移达梦数据库 Java踩坑合集
达梦数据库踩坑合集 文章目录 安装达梦设置大小写不敏感Spring boot引入达梦驱动(两种方式)将jar包打入本地maven仓库使用国内maven仓库(阿里云镜像) 达梦驱动yml配置springboot mybatis-plus整合达梦,如何避免指定数据库名&…...

arm 解决Rk1126 画框颜色变色问题(RGB转NV12)
在Rv1126上直接对Nv12图像进行绘制时,颜色是灰色。故将Nv12转BGR后绘制图像,绘制完成后转成Nv12,BGR的图像颜色是正常的,但是NV12的图像颜色未画全,如图: 1.排查发现是RGB转NV12的函数出现问题,…...

113 链接集10--ctrl+左键单击多选
1.ctrl左键单击多选,单击单选 精简代码 <div class"model-list"><divmousedown.prevent"handleClick(item, $event)"class"model-list-item"v-for"item in modelList":key"item.id":class"{ model…...

详解JavaScript中this指向
this 原理 this 是一个指针型变量,它指向当前函数的运行环境。 1.内存的数据结构 var obj { foo: 5 };2.函数 var obj { foo: function () {} };引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性的value属性。 由于函数是一个单独的…...
c语言之在函数中传递指针
c语言中定义一个函数,如果说是形参一个数组,这个数组在编译后会变成一个指针变量 比如下面的代码例子 #include<stdio.h> void ff(char a[]) {a[1]r;a[4]r;printf("%d\n",a); }int main() {char a[]"peogeam";ff(a);printf(…...
vue2 插槽(默认插槽 slot 、具名插槽 v-slot 、作用域插槽 slot-scope -- 插槽传值 )
插槽:用于在子组件的指定位置插入指定内容,类似在电梯里挂的若干广告显示屏,可以给指定的位置传入指定的广告 单插槽(匿名/默认插槽) 父组件中( 此时的 ) <Child><template><p…...
(第79天)单机转 RAC:19C 单机 到 19C RAC
前言 单机转 RAC 分为两种: 同版本迁移:可以使用 RMAN 或者 ADG 方式升级迁移:建议使用数据泵 或者 XTTS 方式升级迁移使用数据泵的方式与 (第72天)数据泵升级:11GR2 到 19C 步骤基本一致,这里不作演示,只演示使用 ADG 来进行同版本迁移。 升级前准备 本次测试尽量按…...
Spring Cloud微服务Actuator和Vue
目录 前言一、引入Actuator依赖二、暴露Actuator端点1. 配置文件2. 监控端点 三、自定义健康检查自定义健康检查类 四、vue前端代码五、监控器的优势六、监控指标的可视化1. Grafana2. Prometheus 七、安全性考虑安全配置示例 八、总结 前言 随着微服务架构的流行,…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...

RushDB开源程序 是现代应用程序和 AI 的即时数据库。建立在 Neo4j 之上
一、软件介绍 文末提供程序和源码下载 RushDB 改变了您处理图形数据的方式 — 不需要 Schema,不需要复杂的查询,只需推送数据即可。 二、Key Features ✨ 主要特点 Instant Setup: Be productive in seconds, not days 即时设置 :在几秒钟…...
学习 Hooks【Plan - June - Week 2】
一、React API React 提供了丰富的核心 API,用于创建组件、管理状态、处理副作用、优化性能等。本文档总结 React 常用的 API 方法和组件。 1. React 核心 API React.createElement(type, props, …children) 用于创建 React 元素,JSX 会被编译成该函数…...