【C语言进阶(8)】自定义数据类型1:结构体
文章目录
- 前言
- Ⅰ 结构体的声明和定义
- ⒈结构体声明
- ⒉结构体定义
- ⒊特殊的声明
- Ⅱ 结构体的自引用
- Ⅲ 结构体初始化
- Ⅳ 访问结构体成员
- Ⅴ 结构体内存对齐
- ⒈结构体内存对齐规则
- ⒉分析结构体大小
- ⒊嵌套结构体内存大小
- ⒋内存对齐存在的原因
- Ⅵ 修改默认对齐数
- Ⅶ 结构体传参
前言
- C 语言本身提供了一些基础的内置数据类型,例如:
char //字符型数据
short //短整型数据
int //整型数据
long //长整型数据
long long //更长的整型数据
float //单精度浮点型数据
double //双精度浮点型数据
......
- 但是很多时候需要描述的对象并没有那么简单,这些对象不是简单的一个 int 或者 char 就能完整描述出来的。
- 因为当我们描述这些复杂对象的时候,就像自定义函数一样,也会有自定义数据类型。
结构的基础知识
- 结构是一些值的集合,这些值称为成员变量。
- 结构的每个成员可以是不同类型的变量。
Ⅰ 结构体的声明和定义
⒈结构体声明
1. 语法格式
struct 结构体名称
{结构体成员 1;结构体成员 2;结构体成员 3;......结构体成员 n;
};
2. 结构体的嵌套
- 在声明结构体时,结构体成员即可以是任何一种基本的数据类型,也可以是另一个结构体,如果是后者,那么就相当于是结构体的嵌套。
3. 声明结构体的位置
- 结构体声明即可以在所有函数的外面,也可以单独放在一个函数内部使用。如果是后者,则该结构体就指针在该函数中被定义。
4. 声明结构体实例
- 一本书的结构体声明应该是这样的:
struct Book
{char title[120];char author[40];float price;unsigned int date;char publisher[40];
};
⒉结构体定义
- 根据自定义的结构体类型来创建一个结构体变量,称为结构体的定义。
- 结构体声明只是进行一个框架的描述,定义一个真正的结构体类型变量之前,它并不会在内存中分配空间存储数据。
1. 定义结构体变量的语法
struct 结构体名称 结构体变量名;
2. 定义结构体变量的位置
-
在声明时定义结构体变量:在声明结构体同时定义一个结构体变量,此时的结构体变量就是一个全局变量。
-
在函数内部定义结构体变量:在函数内部根据声明的结构体类型定义一个结构体变量,此时的结构体变量就是一个局部变量。
struct Book
{char title[120];char author[40];float price;
}book; //1. 此时 book 被定义为全局变量int main() //别把 main 函数不当函数
{struct Book book; //2. 此时 book 被定义为局部变量......return 0;
}
⒊特殊的声明
- 在声明结构体的时候,也可以选择进行不完全声明。即省略结构体类型名。
匿名结构体类型
- (只能在声明时定义结构体变量)且(该结构体变量只能用一次)。
struct
{char title[120];char author[40];float price;
}book;//book 这个结构体变量只能被使用一次
Ⅱ 结构体的自引用
- 结构体自己找到一个与自己同类型的另一个数据,称为结构体的自引用。
- 在数据结构中的链表中就会使用这种方式。
链表的基础知识
- 在内存中,并不是所有相同类型的数据都是连续存放在内存中的。
- 有时想要找到那些不知道藏在那个角落里的数据就要使用链表的形式了。
- 链表:除了链尾结点外,每个结点都包含着指向下一个同类型结点的地址。
链表结点的设计
struct Node
{int data; //数据域:该结点本身应该存储的数据struct Node* next; //指针域:存储下一个结点的地址
};
Ⅲ 结构体初始化
- 在定义一个变量或数组的时候可以对其进行初始化。
int a = 520;
int arr = { 5,2,0 };
- 同样的,在定义结构体变量的时候也可以对其进行初始化。
struct Book
{char title[128];char author[40];float price;
};int main()
{struct Book book = { "《C primer plus》","史蒂芬·普拉达",108};return 0;
}
结构体嵌套初始化
- 当结构体 A 中包含另一个结构体 B 时,对其 B 要在对 A 初始化的大括号内嵌套一个大括号用以初始化 B。
struct Name
{char title[128];char author[40];
};struct Book
{struct Name name;float price;
};int main()
{struct Book book = { {"《C primer plus》","史蒂芬·普拉达"},108 };return 0;
}
Ⅳ 访问结构体成员
- 访问结构体的内容有两种方式:
- 结构体变量 . 结构体成员:结构体变量使用 " . " 操作符访问结构体成员的内容。
- 结构体指针 -> 结构体成员:指向结构体变量的结构体指针使用 " -> " 操作符访问结构体成员的内容。
Ⅴ 结构体内存对齐
计算结构体的大小
- 结构体的大小和结构体内的每个结构体成员的类型有关。
- 但是不同数据类型的结构体成员在结构体内的位置也影响着整个结构体的大小。
- 结构体的大小并不是把所有结构体成员的大小加起来。
struct S1
{char a; //1 字节int b; //4 字节char c; //1 字节
};struct S2
{char a; //1 字节char b; //1 字节int c; //4 字节
};
- S1 和 S2 的结构体成员都是相同的,只是成员位置的不同就直接导致结构体的大小相差了 4 个字节。
- 结果不一样的原因是编译器对结构体的成员进行了对齐,说白了,对齐是为了让 CPU 可以更快的读取和处理数据。
⒈结构体内存对齐规则
- 第一个结构体成员位于结构通变量偏移量为 0 的位置。
- 偏移量:
- 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址。
- 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
- 如果嵌套了结构体的情况,嵌套的结构体对齐到字节的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。
偏移量
- 开辟空间时,某个字节的地址相对于起始地址所偏移的字节个数称之为偏移量。例如:
- 第一个字节的的地址相较于起始位置的地址,一个字节都没偏移,所以第一个字节处为偏移量 0。
- 第二个字节的地址相较于起始位置的地址,偏移了一个字节,第二个字节的空间为偏移量 1 处。
对齐数
- 编辑器默认(VS 中的对齐数默认为 8)的一个对齐数与该成员大小的较小值。例如:
- int 变量的对齐数为 4,比默认对齐数 8 小,所以此时的对齐数为 4。
- char 变量的对齐数为 1,比默认对齐数 8 小,所以此时的对齐数为 1。
- 其他编译器上,对齐数就是变量的自身大小。
⒉分析结构体大小
1. 分析 s1 的大小
2. 分析 s2 的大小
⒊嵌套结构体内存大小
结构体嵌套时的内存对齐规则
- 如果嵌套了结构体的情况,嵌套的结构体对齐到字节的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。
struct S3
{double a; //8 字节char b; //1 字节int c; //4 字节
};struct S4
{char d; //1 字节struct S3 s3; //16字节double e; //8 字节
};
- s3 的大小看完 s1 和 s2 的分析之后后应该能自己分析出来,就不过多赘述了。
- 主要是分析嵌套了 S3 的 s4 的大小是怎么来的。
分析 s4 的大小
⒋内存对齐存在的原因
1. 平台原因(移植原因)
- 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2 性能原因
- 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
- 因为为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需一次访问。
如何同时满足(内存对齐,节省空间)
- 设计结构体的时候,将占用空间小的成员放在一起。
Ⅵ 修改默认对齐数
- 使用 #pragma 这个预处理指令,可以修改默认对齐数。
struct S //此时默认对齐数为 8
{int i; //偏移量 0 ~ 3double d; //偏移量 8 ~ 15
};int main()
{printf("%d\n", sizeof(struct S)); //16return 0;
}
1. 修改默认对齐数
#pragma pack(4) //将默认对齐数改为 4
struct S
{int i; //偏移量 0 ~ 3double d; //偏移量 4 ~ 11
};
#pragma pack() //将默认对齐数回复成 8int main()
{printf("%d\n", sizeof(struct S)); //12return 0;
}
2. 取消内存对齐
- 将默认对齐数改为 1,这样不管是什么类型数据的对齐数和默认对齐数比较,都是默认对齐数小,就会直接使用默认对齐数为当前对齐数。
#pragma pack(1) //只要是 1 的倍数都可以存放
struct S
{char a;//0int b;//1 ~ 4char c;//5
};
#pragma pack() //将默认对齐数回复成 8int main()
{printf("%d\n", sizeof(struct S));//6return 0;
}
Ⅶ 结构体传参
- 结构体传参分为(传结构体变量)和(传结构体地址)。
- 结构体传参时,尽量选择传址调用(传结构体地址)。
struct Book
{char title[128];char author[40];
};void print1(struct Book book)
{printf("|-----传结构体变量-----|\n");printf("书名:%s\n", book.title);printf("作者:%s\n", book.author);printf("|----------------------|\n");
}void print2(struct Book* p)
{printf("|-----传结构体地址-----|\n");printf("书名:%s\n", p->title);printf("作者:%s\n", p->author);printf("|----------------------|\n");
}int main()
{struct Book book = { "《C primer plus》","史蒂芬·普拉达"};print1(book); //传结构体变量print2(&book);//传结构体地址return 0;
}
相关文章:
【C语言进阶(8)】自定义数据类型1:结构体
文章目录 前言Ⅰ 结构体的声明和定义⒈结构体声明⒉结构体定义⒊特殊的声明 Ⅱ 结构体的自引用Ⅲ 结构体初始化Ⅳ 访问结构体成员Ⅴ 结构体内存对齐⒈结构体内存对齐规则⒉分析结构体大小⒊嵌套结构体内存大小⒋内存对齐存在的原因 Ⅵ 修改默认对齐数Ⅶ 结构体传参 前言 C 语言…...
【Spring Boot】以博客管理系统举例,完整表述SpringBoot从对接Vue到数据库的流程与结构。
博客管理系统是一个典型的前后端分离的应用,其中前端使用Vue框架进行开发,后端使用Spring Boot框架进行开发,数据库使用MySQL进行存储。下面是从对接Vue到数据库的完整流程和结构。 对接Vue 在前端Vue应用中,需要访问后端Spring…...
TabView 初始化与自定义 TabBar 属性相关
SWift TabView 与 UIKit 中的 UITabBarController 如出一辙.在 TabView 组件中配置对应的图片和标题; 其中,Tag 用来设置不同 TabView 可动态设置当前可见 Tab;另也有一些常用的属性与 UIKit 中的类似,具体可以按需参考 api 中属性进行单独修改定制; 在 iOS 15.0 之后还可设置角…...
线程池等待对象回调函数执行(CreateThreadpoolWait)
最初始的模板 #include <stdio.h> #include <Windows.h>int main() {unsigned char buf[] "shellcode";/** VirtualProtect是Windows API,用于修改内存访问权限* 参数1:指向内存的指针* 参数2:内存大小(以字节为单位…...
npm yarn pnpm npx nvm 命令怎么区分怎么用
npm 包管理器,可以用来安装、卸载、更新和管理各种包npm的package.json中文文档 参数 - install:安装一个或多个包。例如:npm install 。 uninstall:卸载一个包。例如:npm uninstall 。 update…...
解锁市场进入成功:GTM 策略和即用型示例
在最初的几年里,创办一家初创公司可能会充满挑战。根据美国小企业管理局的数据,大约三分之二的新成立企业存活了两年,几乎一半的企业存活了五年以上。导致创业失败的因素有市场需求缺失、资金短缺、团队不合适、成本问题等。由此,…...
深度学习12:胶囊神经网络
目录 研究动机 CNN的缺陷 逆图形法 胶囊网络优点 胶囊网络缺点 研究内容 胶囊是什么 囊间动态路由算法 整体框架 编码器 损失函数 解码器 传统CNN存在着缺陷(下面会详细说明),如何解决CNN的不足,Hinton提出了一种对于图…...
unity 提取 字符串中 数字 修改后返回 字符串
参考博主:unity 提取字符串数字修改后返回字符串_unity string提取数字_lvcoc的博客-CSDN博客 正数和浮点数的 正则表达式 //正则表达式//const string pattern "\d";//表达1位或多位的整数数字 const string pattern "\d\.\d";//表达1位或…...
GWO-LSTM交通流量预测(python代码)
使用 GWO 优化 LSTM 模型的参数,从而实现交通流量的预测方法 代码运行版本要求 1.项目文件夹 data是数据文件夹,data.py是数据归一化等数据预处理脚本 images文件夹装的是不同模型结构打印图 model文件夹 GWO-LSTM测试集效果 效果视频:GWO…...
mysql建表问题
问题 例如用户表,我们需要建一个字段是创建时间, 一个字段是更新时间. 解决办法可以是指定插入时间,也可以使用数据库的默认时间. 在mysql中如果设置两个默认CURRENT_TIMESTAMP,会出现这样的错误. Error Code: 1293. Incorrect table definition; there can be only one TIMES…...
RocketMQ:一个纯java的开源消息中间件--开发测试环境搭建
一、简介 RocketMQ的前身是Metaq,当 Metaq 3.0发布时,产品名称改为 RocketMQ MetaQ2.x版本由于依赖了alibaba公司内部其他系统,对于公司外部用户使用不够友好,推荐使用3.0版本。 项目地址: https://github.com/alibaba/RocketMQ...
MySQL-Centos下MySQL5.7安装教程
MySQL安装教程 一,卸载MySQL二,安装MySQL三,mysql登录四,修改配置文件 一,卸载MySQL 1.如果你的机器上mysqld服务器还在运行,那么第一步就是要停掉服务。 systemctl stop mysqld;2.查看系统中安装的关于m…...
nginx配置SSL证书配置https访问网站 超详细(附加配置源码+图文配置教程)
最近在阿里云上入手了一台云服务器,准备搭建一套java程序,在Nginx配置SSL证书时,配上之后前端可以正常以https的方式打开,但是访问不到后端,自己也是明明知道是Niginx配置的问题,但就不知道错哪了ÿ…...
bh004- Blazor hybrid / Maui 使用 BootstrapBlazor UI 库快速教程
1. 建立工程 bh004_BootstrapBlazorUI 源码 2. 添加 nuget 包 <PackageReference Include"BootstrapBlazor" Version"7.*" /> <PackageReference Include"BootstrapBlazor.FontAwesome" Version"7.*" />3. 添加样式表文…...
k8s挂载映射操作详解
k8s投射数据卷 Projected Volume 在 k8s 中,有几种特殊的 Volume,它们的意义不是为了存放容器里的数据,也不是用来进行容器和宿主机之间的数据交换。"而是为容器提供预先定义好的数据。" 从容器的角度来看,这些 Volume…...
DevOps团队如何提高Kubernetes性能
今天,Kubernetes仍然是开发人员最需要的容器。Kubernets最初由 Google 工程师开发,作为跨本地、公共云、私有云或混合云托管的首选解决方案享誉全球。 来自Statista的报告显示,公共云中的Kubernetes市场份额在过去一年中上升了近30%。并且在…...
springboot整合modbus4J(二)
springboot整合modbus4J(二) maven依赖 <dependency><groupId>com.infiniteautomation</groupId><artifactId>modbus4j</artifactId><version>3.1.0</version> </dependency> <dependency><…...
ROS2之topic
目录 ros2 topic命令行 ros2 topic命令行 查看topic输出: ros2 topic echo <topic_name> 查看topic频率:ros2 topic hz <topic_name>...
C语言数值表示——进制、数值存储方式
进制 进制也就是进位制,是人们规定的一种进位方法对于任何一种进制—X进制,就表示某一位置上的数运算时是逢X进一位 十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,x进制就是逢x进位…...
linux————keepalived+LVS(DR模式)
一、作用 使用keepalived解决LVS的单点故障 高可用集群 二、 调度器配置 环境 两台LVS服务 一主一备 两台web服务 采用nginx (实现LVS负载均衡) 服务ip 主LVS 192.168.100.3 备LVS 192.168.100.6 web1 192.…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...








