【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.…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
第7篇:中间件全链路监控与 SQL 性能分析实践
7.1 章节导读 在构建数据库中间件的过程中,可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中,必须做到: 🔍 追踪每一条 SQL 的生命周期(从入口到数据库执行)&#…...

基于Java+VUE+MariaDB实现(Web)仿小米商城
仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意:运行前…...

【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...