C语言自定义类型结构体
variable
adj.易变的,多变的;时好时坏的;可变的,可调节的;
(数)(数字)变量的;(植,动)变异的,变型的;(齿轮)变速的
n.可变性,可变因素;(数学中的)变量,变元;
(计算机)变量(元);(天文)变星的简称;
(东北信风带以北或南半球的东南信风带与西风带之间的)变风区
前言:
在一开始学习C语言时,我们学习的是int,char...(内置类型),之后又学习数组(自定义类型),然后又学习了指针类型,基本的类型我们都学习的差不多了,今天在为大家带来自定义类型中的三大类型:结构体类型、共用体类型和枚举类型。
1.定义
结构体其实就是各种类型数据的结合体。
比如:对于一个学生而言,学生的属性就有他的名字,性别,年级,成绩等等,为了将这些属性都存储在一起,这时就需要新的自定义类型来进行将不同类型的数据进行整合,这就是结构体类型。
2.创建方式
⚀声明方式:
struct str_name
{number_var;number_var;...
};
- struct 创建结构体类型时的关键字
- str_name struct_name结构体类型的名字
- number_var number_varible结构体内的成员变量
注意:
- 结构体类型的成员变量不能被初始化。
- struct str_name这两个合在一起才被称为结构体类型。
- 结构体的声明一定在使用前进行声明不能在后声明。
- 结构体成员变量可以是任何类型,但绝对不可以是成员变量含有自身结构体的结构体。
对于这种结构体是不允许创建的,因为你的结构体成员里面的又有自身的结构体,你这个成员变量的结构体里面又含有结构体,如此下去,结构体里含结构体,那么这个结构体的大小的有多大?答案是:不知道,很大很大很大!!!大到溢出!!!所以这种方式是不允许的!!!
例子:
//以一个学生为例,声明一个结构体
struct Stu
{char name;//名字int age;//年龄int height;//体重int arr[10];//各科的成绩
}
typedef重命名
//以一个学生为例,声明一个结构体
typedef struct Stu //定义的结构体前加上typedef关键字
{char name;//名字int age;//年龄int height;//体重int arr[10];//各科的成绩
}Stu;//在定义完后面加上重新命名的名字
struct Stu S1;//使用struct定义的名字创建变量
Stu S2;//使用typedef重命名的名字创建变量
//不在声明时重命名
typedef struct Stu Stu;//typedef关键字+原名+新名字;
⚁变量创建方式:
A.在声明时
//以一个学生为例,声明一个结构体
struct Stu
{char name;//名字int age;//年龄int height;//体重int arr[10];//各科的成绩
}S1,S2,S3;
//在声明完结构体后,在后面接着创建结构体变量
B.通过结构体类型
//以上面的struct Stu结构体为例
struct Stu S1;//通过结构体类型创建结构体变量
⚂特殊声明:
struct //不声明结构体类型名字
{char name;//名字int age;//年龄int height;//体重int arr[10];//各科的成绩
}S1;//创建结构体变量
- 这种在声明结构体时不声明结构体类型名,而在声明后接着创建结构体变量的操作就称为结构体的匿名声明。
- 对于这种没有将结构体类型名的结构体,就意味着不能通过结构体类型来创建结构体变量,这种只能使用它后面的结构体变量,可以称为一次性结构体。
⚃自引用:
在结构体声明时,我们讨论过不能在结构体内部创建自身的结构体变量进行使用,因为会使得结构体内存大小溢出,那么有什么方法可以实现能在结构体中自引用自己这个结构体呢?
答案是:自己的结构体指针
3.使用方式
⚀访问成员操作:
A.操作符' . '
结构体变量名.成员变量名
str_name.number_var_name1
S1.age = 21;
通过结构体类型变量访问
B.操作符" -> "
结构体指针->成员变量名
str_piont_name.number_var_name1
struct Stu* p;//结构体指针
p->age = 21;
通过结构体指针变量访问
⚁初始化操作:
按照结构体变量初始化的位置分:
A.在声明时创建变量时
B.通过结构体类型创建时
按照成员变量初始化的顺序分:
A.声明时顺序初始化:
B.指定顺序初始化:
结构体的传值or传址 ?
由于结构体在内存中的存储满足内存对齐,就会存在内存浪费,加之结构体时多种的数据类型的集合,内存空间就会非常大,就不推荐使用传值调用,会拷贝数据压栈(在栈区上开辟空间,会浪费空间,溢出等),所以结构体进行调用时最好时传址调用。
4.存储方式
首先我们来看一下下面这个结构体的内存大小:
Why?为啥不是6个字节,不是这几个类型得字节数相加?难道是2倍关系 ?
其实小编可以告诉大家不是啦,结构体在内存中得存储是一种新的方式:内存对齐
那么下面让我们一起看一下什么是内存对齐,小编先为大家介绍内存对齐的规则,嘻嘻
⚀内存对齐规则:
假设有段内存空间,结构体就存储在这上面,那么在存储前先要对这块空间的内存单元进行编号,而成员变量的存储方式就与这些编号有关,这种方式就是内存对齐。
- 第一个成员变量默认从编号0的位置开始存储。
- 后面的成员变量对齐的编号(对齐数)是:{编译器默认的对齐数,成员变量的大小(字节)}min的整数倍。
- 最后结构体的内存空间大小还需满足是:{编译器默认的对齐数,成员变量的大小(字节)}min的整数倍。
注意:
- 如果是结构体里面含有结构体,那么不是按照这结构体的大小去和编译器默认的对其数比较,而是该结构体内部最大的成员变量的字节数去进行比较。
- VS编译器默认的对其数是8,gcc编译器没有默认的对齐数,对其数就是成员变量本身。
例子:
![]()
结构体里嵌套结构体
⚁修改默认对齐数:
对于VS编译器,我们可以通过#pragma操作修改默认对其数:


⚂为什么存在内存对齐?
【补充】
结构体的内存对齐是为了**提高数据访问的效率以及满足特定硬件和操作系统的要求**。具体原因包括:
- 性能优化:CPU访问内存时,对齐的内存可以更快被读取。不对准的内存访问可能会导致多次内存访问才能获取全部数据,降低效率。
- 硬件要求:某些硬件平台要求特定的数据类型必须在特定地址边界上开始,如2的幂次方边界(4字节、8字节等)。
- 减少填充:对齐可以减少或消除数据结构中的填充字节,使得结构更紧凑,节省内存空间。
- 跨平台兼容性:不同的系统可能有不同的对齐要求,对齐可以确保代码在不同平台上的一致性和兼容性。
- 指令集优化:某些CPU指令集在处理对齐数据时更为高效,因此对齐可以提高指令执行的速度。
- 缓存机制:现代CPU的缓存机制通常以特定的对齐边界来存储和检索数据,对齐有助于提高缓存命中率。
- 数据结构对齐规则:结构体的第一个成员与结构体的起始地址对齐,其他成员根据其类型的最大对齐要求进行对齐。
- 默认对齐数:编译器通常有默认的对齐数值,但可以通过编译器指令或特定的编译器选项来修改。
- offsetof宏:在处理结构体时,`offsetof`宏可以用来获取成员在结构体中的偏移量,这对于理解和操作结构体非常有用。
综上所述,结构体的内存对齐是计算机编程中的一个重要概念,它关系到程序的性能、硬件兼容性以及代码的可维护性。了解并正确应用内存对齐规则,对于编写高效且健壮的程序至关重要。
【转载自百度】
5.位段
⚀定义:
- 结构体的位段是一种特殊类型的成员,它允许程序以bit(比特位)为单位来定义结构体成员变量在内存中所占空间的大小。
- 位段的定义是在成员变量后面+冒号+大小(比特位)进行限定大小。
- 成员必须是int,unsigned int或[signed] char,在C99标准中也可以使用其他类型。
- 位段的主要目的是节约存储空间。
int a:5; char b:3;
⚁存储方式:
- 含有位段的结构体进行存储时,按需来开辟空间的,如果是int类型就开4个字节,char类型就开1个字节
- 位段成员是优先存为上个位段开辟空间里,如果下个位段成员存不进上一个位段成员开辟的空间,是舍弃空间还是利用空间是无法确定的。
- 多个位段是可能共用同一块内存空间的。
- 因为只有内存单元有地址,那么对于位段的成员变量的存储是从内存单元的左边开始存还是右边开始存是未知的。
下面以VS编译器为例:
![]()
正确解析 ![]()
错误解析
⚂注意事项:
- 位段中最大位的数目不能确定,比如16位机器最大16,32位机器最大32,写成27,在16位机器会出问题。
- 通过前面的分析,在位段的存储方式上和最大位数上有很大的不确定性,所以位段是不跨平台的,注重可移植的程序应该避免使⽤位段。
- 位段是按位存储的,所以对于位段成员的结构体,不要用scanf取地址存数值,存的数值可能会被截取,就不是想要的数据。
本章内容结束,下章见,拜拜!!!
相关文章:

C语言自定义类型结构体
variable adj.易变的,多变的;时好时坏的;可变的,可调节的; (数)(数字)变量的;(植,动)变异的,变型的࿱…...

【SpringBoot框架篇】37.使用gRPC实现远程服务调用
文章目录 RPC简介gPRC简介protobuf1.文件编写规范2.字段类型3.定义服务(Services) 在Spring Boot中使用grpc1.父工程pom配置2.grpc-api模块2.1.pom配置2.2.proto文件编写2.3.把proto文件编译成class文件 3.grpc-server模块3.1.pom文件和application.yaml3.2.实现grpc-api模块的…...
投资的三个匹配
许多人亏钱都是犯了同样错误,要么对投资的预期过高,要么是投资期限不匹配,要么是波动承受能力不匹配。投资想要赚钱,先解决匹配问题。 1.预期收益率要匹配 就是明确自己做投资,每年想赚多少钱。凡事都要有个目标&…...

[Netty实践] 请求响应同步实现
目录 一、介绍 二、依赖引入 三、公共部分实现 四、server端实现 五、client端实现 六、测试 一、介绍 本片文章将实现请求响应同步,什么是请求响应同步呢?就是当我们发起一个请求时,希望能够在一定时间内同步(线程阻塞&am…...
Java进阶—哈希冲突的解决
1. 什么是哈希冲突 哈希函数:哈希函数是一种将输入数据(键)映射到固定大小范围的输出值(哈希值)的函数。哈希函数通常用于存储 数据存储和检索领域,例如哈希表中。 哈希表:哈希表(Hash Table),也成为哈希映射(Hash Map)或字典&…...
css的border详解
CSS的border属性是一个简写属性,用于设置以下四个边框属性: border-width:定义边框的宽度。可以使用具体的像素值,或者使用预定义的关键字如thin、medium和thick。border-width不支持百分比值。默认情况下,边框的宽度是…...

如何保障消息一定能发送到RabbitMQ?
我们知道,RabbitMQ的消息最终是存储在Queue上的,而在Queue之前还要经过Exchange,那么这个过程中就有两个地方可能导致消息丢失。第一个是Producer到Exchange的过程,第二个是Exchange到Queue的过程。 为了解决这个问题,…...

【web前端】CSS语法
CSS语法 1. CSS语法格式 通常情况下语法格式如下: 选择器{属性名:属性值;属性名:属性值;属性名:属性值;... }2. CSS添加方式 2.1 行内样式 直接将样式写在本行的标签内。 <h1><p style"font-size: 48px; color:red;";>行内样式测试</p></…...

JS+CSS3点击粒子烟花动画js特效
JSCSS3点击粒子烟花动画js特效 JSCSS3点击粒子烟花动画js特效...

docker镜像复制与常见命令
一、前言 最近通过阿里的镜像仓库远程拉取镜像,发现以前的版本不见了,拉取了最新的镜像,有发现版本不配问题。那么想使用老版本的镜像那就要从别的环境获取。于是就需要进行离线镜像复制,打包,上传,重新导入…...

如何在linux环境上部署单机ES(以8.12.2版本为例)
ES安装(以8.12.2版本为例) 首先创建好对应的文件夹然后在对应的文件夹下执行依次这些命令 1.wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.12.2-linux-x86_64.tar.gz 2.wget https://artifacts.elastic.co/downloads/…...

如何利用人工智能技术实现企业营销效率提升10倍(下)
01. AI在私域运营中可扮演重要角色 私域用户体验历程中的不满,对企业来说,无疑是一记沉重的打击。这些不满不仅会让用户感到失望和沮丧,更会在无形中侵蚀企业的各个环节,给业务带来不可估量的损失。 在私域环境中,每…...

【PHP + 代码审计】数组函数
🍬 博主介绍👨🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收…...

Keepalive与idle监测及性能优化
Keepalive 与 idle监测 Keepalive(保活): Keepalive 是一种机制,通常用于TCP/IP网络。它的目的是确保连接双方都知道对方仍然存在并且连接是活动的。这是通过定期发送控制消息(称为keepalive消息)实现的。如果在预定时…...

DS-红黑树(RBTree)
一.红黑树 1.1 红黑树的起源 当对对AVL树做一些结构修改的操作时候,性能较为低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。 因此1972年Rudolf…...

ubuntu 如何使用阿里云盘
你好,我是 shengjk1,多年大厂经验,努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注!你会有如下收益: 了解大厂经验拥有和大厂相匹配的技术等 希望看什么,评论或者私信告诉我! 文章目录 一…...

sqlite3 交叉编译
#1.下载源码并解压 源码路径如下,下载autoconf版本 SQLite Download Page 解压 tar -zxvf sqlite-autoconf-3450200.tar.gz cd sqlite-autoconf-3450200 mkdir build # 2. 配置源代码 # 假设你已经安装了交叉编译工具链,如gcc-arm-linux-gnueabih…...
【AI生成文章】flutter ChangeNotifierProvider 实用场景举例
内容由Ai 大模型生成,不能完全保障真实 ChangeNotifierProvider 是 Flutter 中一个非常实用的工具,用于在应用程序中管理和传递状态。以下是一些实用的场景举例: 1. 用户信息管理 在应用程序中,用户信息(如用户名、…...
【0274】从shared init file或local init file加载relation cache(2 - 1)
上一篇: 【0273】深入分析 relcache(relation descriptor cache)初始化第一阶段(1) 【0264】深入分析relcache(relation descriptor cache)缓存初始化第2阶段(2) 1. 前言 本文内容是作为《【0264】深入分析relcache(relation descriptor cache)缓存初始化第2阶段…...

蓝桥杯-02-2023蓝桥杯c/c++省赛B组题目
参考 2023 年第十四届蓝桥杯 C/C B组省赛题解 2023蓝桥杯c/c省赛B组题目(最全版): A:日期统计 这题方法应该很多,没有和别人讨论想法。我的解法思路是:先 load 函数生成所有这一年的合法日期,然后枚举所有可以从数据…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...

Linux基础开发工具——vim工具
文章目录 vim工具什么是vimvim的多模式和使用vim的基础模式vim的三种基础模式三种模式的初步了解 常用模式的详细讲解插入模式命令模式模式转化光标的移动文本的编辑 底行模式替换模式视图模式总结 使用vim的小技巧vim的配置(了解) vim工具 本文章仍然是继续讲解Linux系统下的…...