【C语言】结构体详解 -《探索C语言的 “小宇宙” 》

目录
- C语言结构体(`struct`)详解
- 结构体概览表
- 1. 结构体的基本概念
- 1.1 结构体定义
- 1.2 结构体变量声明
- 2. 结构体成员的访问
- 2.1 使用点运算符(`.`)访问成员
- 输出
- 2.2 使用箭头运算符(`->`)访问成员
- 输出
- 3. 结构体的初始化
- 3.1 结构体初始化
- 输出
- 3.2 使用指定初始化器
- 输出
- 4. 结构体的大小
- 输出
- 5. 结构体作为函数参数
- 5.1 传递结构体的副本
- 输出
- 5.2 传递结构体指针
- 输出
- 6. 结构体的嵌套
- 输出
- 7. 结构体与数组
- 输出
- 8. 结构体的内存对齐
- 8.1 对齐示例
- 输出
- 8.2 结构体对齐与`#pragma pack`
- 输出
- 9. 类型定义(`typedef`)简化结构体声明
- 输出
- 10. 嵌入式系统中的应用
- 10.1 示例:硬件寄存器配置
- 输出
- 11. 拓展技巧
- 11.1 结构体指针的算术运算
- 输出
- 11.2 结构体与联合体(`union`)的比较
- 示例:结构体与联合体的比较
- 输出
- 7. 结束语
- 相关文章:
C语言结构体(struct)详解
结构体概览表
| 功能 | 描述 |
|---|---|
| 定义结构体 | 定义一个结构体类型 |
| 声明结构体变量 | 声明一个结构体变量 |
| 访问成员 | 使用点运算符(.)和箭头运算符(->)访问成员 |
| 初始化结构体 | 在声明时初始化结构体 |
| 计算大小 | 使用sizeof计算结构体的大小 |
| 作为函数参数 | 传递结构体或结构体指针作为函数参数 |
| 结构体嵌套 | 结构体中包含其他结构体 |
| 结构体与数组 | 结构体作为数组元素或包含数组的成员 |
| 内存对齐 | 结构体的内存对齐和填充 |
类型定义(typedef) | 使用typedef简化结构体声明 |
| 嵌入式应用 | 在嵌入式系统中使用结构体 |
| 拓展技巧 | 结构体指针运算和联合体比较 |
1. 结构体的基本概念
1.1 结构体定义
结构体通过struct关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
struct Person {char name[50];int age;float height;
};
在上面的示例中,定义了一个Person结构体,其中包含三个成员:name(字符数组)、age(整数)和height(浮点数)。
1.2 结构体变量声明
定义结构体后,可以声明结构体变量来使用它。例如:
struct Person person1;
这里声明了一个Person结构体类型的变量person1。
2. 结构体成员的访问
2.1 使用点运算符(.)访问成员
可以通过点运算符(.)访问结构体的成员变量。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};int main() {struct Person person1;// 初始化结构体成员person1.age = 25;person1.height = 175.5;snprintf(person1.name, sizeof(person1.name), "Alice");// 输出结构体成员printf("Name: %s\n", person1.name);printf("Age: %d\n", person1.age);printf("Height: %.2f\n", person1.height);return 0;
}
输出
Name: Alice
Age: 25
Height: 175.50
2.2 使用箭头运算符(->)访问成员
如果结构体变量是指针类型,则可以通过箭头运算符(->)访问其成员。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};void printPerson(struct Person *p) {printf("Name: %s\n", p->name);printf("Age: %d\n", p->age);printf("Height: %.2f\n", p->height);
}int main() {struct Person person1 = {"Bob", 30, 180.0};struct Person *ptr = &person1;printPerson(ptr);return 0;
}
输出
Name: Bob
Age: 30
Height: 180.00
3. 结构体的初始化
3.1 结构体初始化
可以在定义结构体变量的同时进行初始化。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};int main() {struct Person person2 = {"Alice", 30, 160.0};printf("Name: %s\n", person2.name);printf("Age: %d\n", person2.age);printf("Height: %.2f\n", person2.height);return 0;
}
输出
Name: Alice
Age: 30
Height: 160.00
3.2 使用指定初始化器
C99标准引入了指定初始化器,可以按顺序或指定成员进行初始化。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};int main() {struct Person person3 = {.age = 40, .height = 180.0, .name = "Bob"};printf("Name: %s\n", person3.name);printf("Age: %d\n", person3.age);printf("Height: %.2f\n", person3.height);return 0;
}
输出
Name: Bob
Age: 40
Height: 180.00
4. 结构体的大小
结构体的大小取决于其成员的数量和类型,以及内存对齐的规则。可以使用sizeof运算符来获取结构体的大小。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};int main() {printf("Size of Person: %zu bytes\n", sizeof(struct Person));return 0;
}
输出
在不同平台上的输出可能不同,例如:
- 32位系统:
Size of Person: 60 bytes - 64位系统:
Size of Person: 64 bytes
5. 结构体作为函数参数
5.1 传递结构体的副本
结构体可以作为函数参数传递。如果传递的是结构体的副本,则会创建结构体的一个副本,可能会影响性能。
#include <stdio.h>struct Person {char name[50];int age;float height;
};void printPerson(struct Person p) {printf("Name: %s\n", p.name);printf("Age: %d\n", p.age);printf("Height: %.2f\n", p.height);
}int main() {struct Person person1 = {"Alice", 30, 160.0};printPerson(person1);return 0;
}
输出
Name: Alice
Age: 30
Height: 160.00
5.2 传递结构体指针
为了提高效率,可以将结构体的指针传递给函数,这样只需传递指针而不是整个结构体。
#include <stdio.h>struct Person {char name[50];int age;float height;
};void updateAge(struct Person *p, int newAge) {p->age = newAge;
}int main() {struct Person person1 = {"Bob", 30, 180.0};updateAge(&person1, 35);printf("Updated Age: %d\n", person1.age);return 0;
}
输出
Updated Age: 35
6. 结构体的嵌套
结构体可以嵌套其他结构体。例如:
#include <stdio.h>struct Address {char street[100];char city[50];int postalCode;
};struct Person {char name[50];int age;struct Address address; // 嵌套的结构体
};int main() {struct Person person4 = {"John",28,{"123 Main St", "Metropolis", 12345}};printf("Name: %s\n", person4.name);printf("Address: %s, %s %d\n", person4.address.street, person4.address.city, person4.address.postalCode);return 0;
}
输出
Name: John
Address: 123 Main St, Metropolis 12345
7. 结构体与数组
结构体可以作为数组的元素,也可以包含数组作为成员。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};int main() {struct Person people[2] = {{"Alice", 30, 160.0},{"Bob", 40, 180.0}};for (int i = 0; i < 2; i++) {printf("Person %d: %s, %d, %.2f\n", i+1, people[i].name, people[i].age, people[i].height);}return 0;
}
输出
Person 1: Alice, 30, 160.00
Person 2: Bob, 40, 180.00
8. 结构体的内存对齐
结构体的内存对齐与填充是为了提高数据访问的效率。在C语言中,结构体的内存布局可能会受到对齐要求的影响,导致结构体的实际大小可能大于成员变量总和的大小。编译器通常会在成员之间插入填充字节,以确保每个成员的地址对齐。
8.1 对齐示例
#include <stdio.h>struct Example {char c; // 1 byteint i; // 4 bytes, 3 bytes of paddingshort s; // 2 bytes
};int main() {printf("Size of Example: %zu bytes\n", sizeof(struct Example));return 0;
}
输出
Size of Example: 12 bytes
在这个例子中,Example结构体的大小是12字节。虽然char占1字节,int占4字节,short占2字节,成员变量的总和为7字节,但由于内存对齐要求,Example结构体实际上占用12字节。
8.2 结构体对齐与#pragma pack
在某些情况下,可以使用#pragma pack指令来控制结构体的对齐方式,从而减少内存占用。
#include <stdio.h>#pragma pack(1) // 设置结构体对齐为1字节struct PackedExample {char c;int i;short s;
};#pragma pack() // 恢复默认对齐int main() {printf("Size of PackedExample: %zu bytes\n", sizeof(struct PackedExample));return 0;
}
输出
Size of PackedExample: 7 bytes
使用#pragma pack(1)可以将PackedExample结构体的对齐方式设置为1字节,从而减少结构体的实际大小为7字节,但可能会影响访问效率。
9. 类型定义(typedef)简化结构体声明
使用typedef可以为结构体定义一个新的类型名,使得结构体的声明更加简洁。例如:
#include <stdio.h>typedef struct {char name[50];int age;float height;
} Person;int main() {Person person1 = {"Charlie", 28, 175.0};printf("Name: %s\n", person1.name);printf("Age: %d\n", person1.age);printf("Height: %.2f\n", person1.height);return 0;
}
输出
Name: Charlie
Age: 28
Height: 175.00
10. 嵌入式系统中的应用
在嵌入式系统中,结构体用于管理硬件寄存器、配置参数以及存储设备状态等。结构体能够帮助开发者以更结构化的方式访问硬件资源,提高代码的可读性和维护性。
10.1 示例:硬件寄存器配置
#include <stdio.h>
#include <stdint.h>// 定义硬件寄存器配置结构体
typedef struct {volatile uint32_t CONTROL;volatile uint32_t STATUS;volatile uint32_t DATA;
} UART_RegDef_t;int main() {UART_RegDef_t UART1; // 假设这是一个UART寄存器的实例// 设置UART寄存器UART1.CONTROL = 0x01; // 启用UARTUART1.STATUS = 0x00; // 清除状态UART1.DATA = 0x55; // 发送数据// 打印寄存器的配置printf("UART1 CONTROL: 0x%X\n", UART1.CONTROL);printf("UART1 STATUS: 0x%X\n", UART1.STATUS);printf("UART1 DATA: 0x%X\n", UART1.DATA);return 0;
}
输出
UART1 CONTROL: 0x1
UART1 STATUS: 0x0
UART1 DATA: 0x55
在这个示例中,结构体UART_RegDef_t用于表示UART寄存器的配置,包含CONTROL、STATUS和DATA寄存器。通过这种方式,可以方便地设置和读取寄存器的值。
11. 拓展技巧
11.1 结构体指针的算术运算
可以对结构体指针进行算术运算,通常用于数组访问。例如:
#include <stdio.h>struct Person {char name[50];int age;float height;
};int main() {struct Person people[3] = {{"Alice", 30, 160.0},{"Bob", 40, 180.0},{"Charlie", 25, 170.0}};struct Person *ptr = people; // 指向结构体数组的指针for (int i = 0; i < 3; i++) {printf("Person %d: %s, %d, %.2f\n", i+1, (ptr+i)->name, (ptr+i)->age, (ptr+i)->height);}return 0;
}
输出
Person 1: Alice, 30, 160.00
Person 2: Bob, 40, 180.00
Person 3: Charlie, 25, 170.00
11.2 结构体与联合体(union)的比较
结构体和联合体都可以存储多个数据项,但结构体的每个成员都占有独立的内存空间,而联合体的所有成员共享同一块内存。使用结构体时每个成员都可用,而使用联合体时只有一个成员可以使用。
示例:结构体与联合体的比较
#include <stdio.h>typedef union {int intValue;float floatValue;char charValue;
} UnionType;typedef struct {int intValue;float floatValue;char charValue;
} StructType;int main() {UnionType u;StructType s;u.intValue = 10;printf("Union intValue: %d\n", u.intValue);u.floatValue = 5.5; // 修改联合体中的值printf("Union floatValue: %f\n", u.floatValue);// 注意:这时intValue的值是不确定的s.intValue = 10;s.floatValue = 5.5;s.charValue = 'A';printf("Struct intValue: %d\n", s.intValue);printf("Struct floatValue: %f\n", s.floatValue);printf("Struct charValue: %c\n", s.charValue);return 0;
}
输出
Union intValue: 10
Union floatValue: 5.500000
Struct intValue: 10
Struct floatValue: 5.500000
Struct charValue: A
7. 结束语
- 本节内容已经全部介绍完毕,希望通过这篇文章,大家对C语言中的结构体
struct有了更深入的理解和认识。- 感谢各位的阅读和支持,如果觉得这篇文章对你有帮助,请不要吝惜你的点赞和评论,这对我们非常重要。再次感谢大家的关注和支持!点我关注❤️
相关文章:
- 指针的神秘探险:从入门到精通的奇幻之旅 !
相关文章:
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
目录 C语言结构体(struct)详解结构体概览表1. 结构体的基本概念1.1 结构体定义1.2 结构体变量声明 2. 结构体成员的访问2.1 使用点运算符(.)访问成员输出 2.2 使用箭头运算符(->)访问成员输出 3. 结构体…...
基于DTW距离的KNN算法实现股票高相似筛选案例
使用DTW算法简单实现曲线的相似度计算-CSDN博客 前文中股票高相关k线筛选问题的延伸。基于github上的代码迁移应用到股票高相关预测上。 这里给出一个相关完整的代码实现案例。 1、数据准备 假设你已经有了一些历史股票的k线数据。如果数据能打标哪些股票趋势是上涨的、下跌…...
GD32 - IIC程序编写
一、初始化 理论知识链接: IIC理论知识 二、代码实现 1、SDA和SCL设置成开漏输出模式 开漏输出的作用: 因为IIC总线是一种双向的通信协议,需要使用开漏输出实现共享总线。开漏输出类似于一种线与的方式,即无论总线上哪个设备…...
将项目部署到docker容器上
通过docker部署前后端项目 前置条件 需要在docker中拉去jdk镜像、nginx镜像 docker pull openjdk:17 #拉取openjdk17镜像 docker pull nginx #拉取nginx镜像部署后端 1.打包后端项目 点击maven插件下面的Lifecycle的package 对后端项目进行打包 等待打包完成即可 2.将打…...
免费【2024】springboot宠物美容机构CRM系统设计与实现
博主介绍:✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围:SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…...
搞懂数据结构与Java实现
文章链接:搞懂数据结构与Java实现 (qq.com) 代码链接: Java实现数组模拟循环队列代码 (qq.com) Java实现数组模拟栈代码 (qq.com) Java实现链表代码 (qq.com) Java实现哈希表代码 (qq.com) Java实现二叉树代码 (qq.com) Java实现图代码 (qq.com)...
Stable Diffusion 图生图
区别于文生图,所谓的图生图,俗称的垫图,就是比文生图多了一张参考图,由参考一张图来生成图片,影响这个图片的要素不仅只靠提示词了,还有这个垫图的因素,这个区域就上上传垫图的地方,…...
语言转文字
因为工作原因需要将语音转化为文字,经常搜索终于找到一个免费的好用工具,记录下使用方法 安装Whisper 搜索Colaboratory 右上方链接服务 执行 !pip install githttps://github.com/openai/whisper.git !sudo apt update && sudo apt install f…...
ref函数
Vue2 中的ref 首先我们回顾一下 Vue2 中的 ref。 ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例࿱…...
7/30 bom和dom
文档对象mox 浏览器对象模型...
【Golang 面试 - 进阶题】每日 3 题(五)
✍个人博客:Pandaconda-CSDN博客 📣专栏地址:http://t.csdnimg.cn/UWz06 📚专栏简介:在这个专栏中,我将会分享 Golang 面试中常见的面试题给大家~ ❤️如果有收获的话,欢迎点赞👍收藏…...
MySQL,GROUP BY子句的作用是什么?having和where的区别在哪里说一下jdbc的流程
GROUP BY 子句的作用是什么 GROUP BY 字段名 将数据按字段值相同的划为一组,经常配合聚合函数一起使用。 having和where的区别在哪里 where是第一次检索数据时候添加过滤条件,确定结果集。而having是在分组之后添加结果集,用于分组之后的过…...
1._专题1_双指针_C++
双指针 常见的双指针有两种形式,一种是对撞指针,一种是左右指针。对撞指针:一般用于顺序结构中,也称左右指针。 对撞指针从两端向中间移动。一个指针从最左端开始,另一个从最右端开始,然后逐渐往中间逼近…...
Spring集成ES
RestAPI ES官方提供的java语言客户端用以组装DSL语句,再通过http请求发送给ES RestClient初始化 引入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </d…...
力扣高频SQL 50题(基础版)第二十六题
文章目录 力扣高频SQL 50题(基础版)第二十六题1667.修复表中的名字题目说明实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题(基础版)第二十六题 1667.修复表中的名字 题目说明 表: Users ----------------…...
WIFI 接收机和发射机同步问题+CFO/SFO频率偏移问题
Synchronization Between Sender and Receiver & CFO Correction 解决同步问题和频率偏移问题是下面论文的关键,接下来结合论文进行详细解读 解读论文:Verification and Redesign of OFDM Backscatter 论文pdf:https://www.usenix.org/s…...
ubuntu安装并配置flameshot截图软件
参考:flameshot key-bindins 安装 sudo apt install flameshot自定义快捷键 Settings->Keyboard->View and Customize Shortcuts->Custom Shortcuts,输入该快捷键名称(自定义),然后输入command(…...
【Linux】CentOS更换国内阿里云yum源(超详细)
目录 1. 前言2. 打开终端3. 确保虚拟机已经联网4. 备份现有yum配置文件5. 下载阿里云yum源6. 清理缓存7. 重新生成缓存8. 测试安装gcc 1. 前言 有些同学在安装完CentOS操作系统后,在系统内安装比如:gcc等软件的时候出现这种情况:(…...
Leetcode49. 字母异位词分组(java实现)
今天我来给大家分享的是leetcode49的解题思路,题目描述如下 如果没有做过leetcode242题目的同学,可以先把它做了,会更好理解异位词的概念。 本道题的大题思路是: 首先遍历strs,然后统计每一个数组元素出现的次数&#…...
OpenJudge | 字符串中最长的连续出现的字符
总时间限制: 1000ms 内存限制: 65536kB 描述 求一个字符串中最长的连续出现的字符,输出该字符及其出现次数,字符串中无空白字符(空格、回车和tab),如果这样的字符不止一个,则输出第一个 输入 首先输入N…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
