C语言:自定义类型:结构体
文章目录前言1.什么是结构体2.结构体类型的声明2.1结构的声明2.2 结构体变量的创建和初始化2.3 结构的特殊声明2.4 结构体的自引用3.结构体内存对齐3.1 对齐规则3.2 为什么需要内存对齐3.3 修改默认对齐数3.4 结构体传参4.结构体实现位段4.1 位段的定义4.2 位段的内存分配4.3 位段的注意事项前言在 C 语言的世界里我们早已熟悉了int、char、float等内置的基本数据类型。它们能很好地表示单个的数值或字符。然而现实世界中的数据往往是复杂且相互关联的比如一个学生的信息学号、姓名、成绩或者一个坐标点x, y。为了描述这些由多个不同类型数据组合而成的实体C 语言提供了强大的“自定义类型”机制。结构体正是自定义类型中最核心、最常用的一员。它允许我们将多个不同类型的变量“打包”成一个整体从而创建出符合我们业务逻辑的新数据类型。理解并掌握结构体是迈向 C 语言中级编程乃至学习数据结构如链表、树的必经之路。1.什么是结构体结构体是 C 语言中一种用户自定义的复合数据类型。它允许你将多个不同类型的变量称为“成员”组合在一起形成一个逻辑上的整体用来描述一个具有多个属性的实体。2.结构体类型的声明2.1结构的声明声明一个结构体类型就是定义这个“数据包”的模板告诉编译器这个新类型叫什么名字里面包含哪些成员变量。声明本身不分配内存只有用这个类型去声明变量时才会分配。结构体类型的声明使用struct关键字基本格式如下struct结构体标签{数据类型 成员1;数据类型 成员2;// ... 更多成员};structC 语言关键字表示开始定义一个结构体类型。结构体标签给这个结构体类型起的名字用于后续引用。例如Student、Point。{}大括号内是成员列表定义了结构体包含哪些数据。; 结构体声明末尾的分号不能省略。例如声明一个表示学生的结构体类型structStudent{charname[20];// 姓名字符数组成员intage;// 年龄整型成员floatscore;// 成绩浮点型成员};// 注意分号这里我们声明了一个名为struct Student的新类型。它包含三个成员name、age、score。2.2 结构体变量的创建和初始化声明了结构体类型后就可以用它来创建变量称为结构体变量并为其赋值初始化。#includestdio.h// 声明一个学生结构体类型三个成员structStu{charname[20];// 名字intage;// 年龄charsex[5];// 性别};intmain(){// 1. 按照结构体成员的顺序初始化structStus1{张三,20,男};printf(name: %s\n,s1.name);printf(age : %d\n,s1.age);printf(sex : %s\n,s1.sex);// 2. 按照指定的顺序初始化使用“.”成员运算符structStus2{.age18,.name李四,.sex女};printf(\nname: %s\n,s2.name);printf(age : %d\n,s2.age);printf(sex : %s\n,s2.sex);return0;}2.3 结构的特殊声明除了前面介绍的标准声明方式C 语言还允许一种特殊的结构体声明即匿名结构体类型也称为“无标签结构体”。这种声明方式省略了结构体标签通常用于一次性定义变量或者嵌套在其他结构体中。匿名结构体类型的声明格式如下struct{数据类型 成员1;数据类型 成员2;// ... 更多成员}变量名1,变量名2,...;由于没有标签这种类型只能在声明的同时定义变量之后无法再用这个类型去创建新的变量。#includestdio.hintmain(){// 声明一个匿名结构体类型并同时定义两个变量 point1, point2struct{intx;inty;}point1,point2;// 为变量赋值point1.x10;point1.y20;point2.x30;point2.y40;printf(point1: (%d, %d)\n,point1.x,point1.y);printf(point2: (%d, %d)\n,point2.x,point2.y);return0;}匿名结构体常与typedef关键字结合为其创建一个别名从而变相地“命名”这个类型使其可以重复使用。#includestdio.h// 使用 typedef 为匿名结构体类型创建一个别名 Pointtypedefstruct{intx;inty;}Point;intmain(){Point p1{5,10};// 现在可以使用别名 Point 来定义变量Point p2{20,30};printf(p1: (%d, %d)\n,p1.x,p1.y);printf(p2: (%d, %d)\n,p2.x,p2.y);return0;}这种方式结合了匿名结构体的简洁性和typedef带来的可复用性是实践中常见的一种用法。2.4 结构体的自引用结构体的自引用是指一个结构体类型中包含一个指向自身类型实例的指针成员。这是实现链表、树等递归数据结构的基础。示例链表节点structNode{intdata;// 节点数据structNode*next;// 指向下一个节点的指针};这里next是一个指向struct Node类型的指针而不是struct Node本身那会导致无限大小。通过这种方式多个节点可以连接成链。3.结构体内存对齐结构体内存对齐是编译器为了提高内存访问效率而采用的一种内存布局规则。它要求结构体的每个成员在内存中的起始地址必须是其自身类型大小或编译器指定对齐值的整数倍。3.1 对齐规则结构体的第1个成员对齐到和结构体变量起始位置偏移量为0的地址处。从第2个成员变量开始都要对齐到某个对齐数的整数倍的地址处。对齐数 编译器默认的一个对齐数 与 该成员变量大小的较小值。VS 中默认的值为 8Linux 中 gcc 没有默认对齐数对齐数就是成员自身的大小。结构体总大小为最大对齐数结构体中每个成员变量都有一个对齐数所有对齐数中最大的的整数倍。如果嵌套了结构体的情况嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍处结构体的整体大小就是所有最大对齐数含嵌套结构体中成员的对齐数的整数倍。#include stdio.h struct Example1 { char a; // 1 字节偏移 0 int b; // 4 字节偏移必须是 4 的倍数所以从 4 开始 char c; // 1 字节偏移 8 }; // 总大小1 3填充 4 1 9 → 需补齐到 4 的倍数 → 12 字节 struct Example2 { int b; // 4 字节偏移 0 char a; // 1 字节偏移 4 char c; // 1 字节偏移 5 }; // 总大小4 1 1 6 → 需补齐到 4 的倍数 → 8 字节 int main() { printf(sizeof(struct Example1) %zu\n, sizeof(struct Example1)); // 输出 12 printf(sizeof(struct Example2) %zu\n, sizeof(struct Example2)); // 输出 8 return 0; }Example1因int b需要 4 字节对齐char a后填充了 3 字节导致总大小为 12。Example2通过调整成员顺序减少了填充总大小仅为 8。3.2 为什么需要内存对齐性能CPU 通常按对齐的字word读取内存未对齐的访问可能导致多次内存读取或硬件异常降低效率。平台兼容性某些硬件架构如 ARM、x86要求严格对齐否则会引发总线错误。3.3 修改默认对齐数我们可以使用#pragma pack(n)指令来修改默对齐数。#pragmapack(1)// 修改默认对齐数为1structPackedStruct{chara;intb;charc;};// sizeof 1 4 1 6#pragmapack()// 恢复默认对齐3.4 结构体传参在 C 语言中结构体作为函数参数传递时通常建议传递结构体的地址即指针而不是直接传递整个结构体变量。主要原因如下效率直接传递结构体值传递会导致整个结构体的数据被复制一份给形参。如果结构体很大包含多个成员或数组成员这种复制会消耗较多时间和栈空间。传递指针只复制一个地址通常 4 或 8 字节效率更高。修改原数据如果函数需要修改调用者传入的结构体成员必须通过指针传递。值传递只是操作副本对原结构体没有影响。#includestdio.hstructStudent{charname[20];intage;floatscore;};// 值传递效率低且无法修改原结构体voidprint1(structStudentstu){printf(姓名: %s, 年龄: %d, 成绩: %.1f\n,stu.name,stu.age,stu.score);// stu.age 25; // 修改只影响副本不影响 main 中的 s1}// 地址传递推荐高效且可以修改原结构体voidprint2(structStudent*pStu){printf(姓名: %s, 年龄: %d, 成绩: %.1f\n,pStu-name,pStu-age,pStu-score);pStu-age25;// 通过指针修改原结构体的成员}intmain(){structStudents1{张三,20,90.5};printf(值传递调用前: %d\n,s1.age);// 输出 20print1(s1);printf(值传递调用后: %d\n,s1.age);// 仍为 20未改变printf(\n地址传递调用前: %d\n,s1.age);// 输出 20print2(s1);// 传递 s1 的地址printf(地址传递调用后: %d\n,s1.age);// 输出 25已被修改return0;}4.结构体实现位段位段Bit-field是 C 语言中一种特殊的结构体成员它允许我们以位为单位来指定成员所占的内存长度从而更精细地控制内存使用。4.1 位段的定义位段通过在结构体成员声明后加上冒号和位数来定义struct 结构体标签 { 类型 成员名1 : 位数; 类型 成员名2 : 位数; // ... };类型必须是整型int、unsigned int、signed int、char等或枚举类型。位数指定该成员占用的二进制位数不能超过类型本身的位数例如int通常为 32 位则位数不能超过 32。示例定义一个表示 RGB565 颜色的位段#includestdio.hstructRGB565{unsignedintred:5;// 红色分量占 5 位unsignedintgreen:6;// 绿色分量占 6 位unsignedintblue:5;// 蓝色分量占 5 位};intmain(){structRGB565color;color.red31;// 5 位最大值2^5 - 1 31color.green63;// 6 位最大值2^6 - 1 63color.blue31;printf(RGB565 颜色值R%u, G%u, B%u\n,color.red,color.green,color.blue);printf(结构体大小%zu 字节\n,sizeof(structRGB565));// 通常为 2 字节16 位return0;}4.2 位段的内存分配位段的内存分配遵循以下规则位段的成员可以是int、unsigned int、signed int或者是char等整型类型。位段的空间上是按照需要以 4 个字节int或者 1 个字节char的方式来开辟的。编译器会为位段分配一个或多个“存储单元”当一个存储单元不足以容纳下一个位段时会开辟新的存储单元。位段涉及很多不确定因素例如位段成员在存储单元内的存放方向、是否允许跨存储单元等位段是不跨平台的注重可移植的程序应该避免使用位段。4.3 位段的注意事项位段的跨平台问题位段的可移植性差主要体现在以下几个方面int位段被当成有符号数还是无符号数是不确定的**。不同编译器可能对未显式声明signed或unsigned的int位段做不同解释。位段中最大位的数目不能确定。例如16 位机器上int位段最大为 16 位32 位机器上最大为 32 位。若将位段位数写成 27在 16 位机器上会出问题。位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。不同编译器、不同平台可能采用不同的方向。当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的。编译器可能选择将第二个位段放入新的存储单元也可能利用当前单元剩余位如果空间足够但跨边界规则允许。取地址操作不能对位段成员使用取地址运算符因为位段的几个成员共有同一个字节这样有些成员的起始位置并不是某个字节的起始位置那么这些位置处是没有地址的。那么就不能使⽤scanf直接给位段的成员输⼊值只能是先输⼊放在一个变量中然后赋值给位段的成员。struct A { int _a : 2; int _b : 5; int _c : 10; int _d : 30; }; int main() { struct A sa { 0 }; scanf(%d, sa._b);//这是错误的 //正确的⽰范 int b 0; scanf(%d, b); sa._b b; return 0; }未命名位段可以定义没有名字的位段用于占位或填充以达到特定的内存对齐效果。structPadding{unsignedinta:4;unsignedint:4;// 未命名位段占 4 位用于填充unsignedintb:8;};零长度位段位段长度可以为 0表示强制下一个位段从新的存储单元开始。structForceAlign{unsignedinta:10;unsignedint:0;// 零长度位段强制 b 从下一个存储单元开始unsignedintb:10;};

相关新闻

VMware Workstation Pro 17 保姆级安装与使用教程

VMware Workstation Pro 17 保姆级安装与使用教程

在软件开发、系统测试或学习新操作系统时,你是否曾因频繁重装系统、担心软件冲突或需要隔离环境而烦恼?虚拟机技术正是解决这些痛点的利器。VMware Workstation Pro 作为行业标杆的桌面虚拟化软件,允许你在单一物理机上同时运行多个独立的操作…

2026/8/10 11:45:40 阅读更多 →
VXE-Table 4.x 实战:性能优化与复杂表格开发指南

VXE-Table 4.x 实战:性能优化与复杂表格开发指南

1. VXE-Table 4.x 实战规范概述作为前端开发中高频使用的表格组件,VXE-Table 4.x 版本在复杂业务场景下的表现直接影响用户体验。最近在金融数据报表项目中,我们深度使用了列配置、合并单元格和虚拟滚动三大核心功能,期间遇到了卡顿、渲染错乱…

2026/8/10 11:45:40 阅读更多 →
GPU加速可变字体变形:Knot-Lattice Blend技术实现高性能动态文字渲染

GPU加速可变字体变形:Knot-Lattice Blend技术实现高性能动态文字渲染

如果你在开发一个需要动态字体效果的Web应用或游戏,比如让标题文字平滑地从一种风格过渡到另一种风格,或者实时响应用户交互改变字体形态,你很可能遇到过这个难题:如何在保证高性能的同时,实现高质量的矢量字体变形&am…

2026/8/10 11:45:40 阅读更多 →

最新新闻

Themosis Framework48 核心解析:打造高效WordPress开发体验的终极指南

Themosis Framework48 核心解析:打造高效WordPress开发体验的终极指南

Themosis Framework48 核心解析:打造高效WordPress开发体验的终极指南 【免费下载链接】framework The Themosis framework core. 项目地址: https://gitcode.com/gh_mirrors/framework48/framework Themosis Framework48 是一款专为 WordPress 开发者打造的…

2026/8/10 18:10:39 阅读更多 →
为什么选择Azure DevOps CLI Extension?10个让开发效率倍增的命令技巧

为什么选择Azure DevOps CLI Extension?10个让开发效率倍增的命令技巧

为什么选择Azure DevOps CLI Extension?10个让开发效率倍增的命令技巧 【免费下载链接】azure-devops-cli-extension Azure DevOps Extension for Azure CLI 项目地址: https://gitcode.com/gh_mirrors/az/azure-devops-cli-extension Azure DevOps CLI Exte…

2026/8/10 18:10:39 阅读更多 →
量子编程入门:5分钟用Qiskit创建你的第一个量子程序

量子编程入门:5分钟用Qiskit创建你的第一个量子程序

量子编程入门:5分钟用Qiskit创建你的第一个量子程序 【免费下载链接】qiskit Qiskit is an open-source SDK for working with quantum computers at the level of extended quantum circuits, operators, and primitives. 项目地址: https://gitcode.com/gh_mirr…

2026/8/10 18:10:39 阅读更多 →
Azure Data Lake Storage Gen2传输:AzCopy v10专项优化

Azure Data Lake Storage Gen2传输:AzCopy v10专项优化

Azure Data Lake Storage Gen2传输:AzCopy v10专项优化 【免费下载链接】azure-storage-azcopy The new Azure Storage data transfer utility - AzCopy v10 项目地址: https://gitcode.com/gh_mirrors/az/azure-storage-azcopy Azure Data Lake Storage Gen…

2026/8/10 18:10:39 阅读更多 →
5分钟掌握!国家中小学智慧教育平台电子课本PDF下载完整指南

5分钟掌握!国家中小学智慧教育平台电子课本PDF下载完整指南

5分钟掌握!国家中小学智慧教育平台电子课本PDF下载完整指南 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课本内容。 项目…

2026/8/10 18:10:39 阅读更多 →
5分钟创建你的专属桌面伙伴:DyberPet终极桌面宠物框架指南 [特殊字符]

5分钟创建你的专属桌面伙伴:DyberPet终极桌面宠物框架指南 [特殊字符]

5分钟创建你的专属桌面伙伴:DyberPet终极桌面宠物框架指南 🐾 【免费下载链接】DyberPet Desktop Cyber Pet Framework based on PySide6 项目地址: https://gitcode.com/GitHub_Trending/dy/DyberPet 厌倦了单调的电脑桌面?想让喜欢的…

2026/8/10 18:09:39 阅读更多 →

日新闻

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南

GraphQL-CSS API全解析:useGqlCSS、GqlCSS组件与getStyles实用指南 【免费下载链接】graphql-css A blazing fast CSS-in-GQL™ library. 项目地址: https://gitcode.com/gh_mirrors/gr/graphql-css GraphQL-CSS是一个基于GraphQL的CSS-in-GQL™库&#xff0…

2026/8/10 0:00:02 阅读更多 →
告别语言障碍:KISS Translator 双语翻译插件终极指南

告别语言障碍:KISS Translator 双语翻译插件终极指南

告别语言障碍:KISS Translator 双语翻译插件终极指南 【免费下载链接】kiss-translator A simple, open source bilingual translation extension & Greasemonkey script (一个简约、开源的 双语对照翻译扩展 & 油猴脚本) 项目地址: https://gitcode.com/…

2026/8/10 0:00:02 阅读更多 →
BepInEx配置管理器:游戏插件配置的终极可视化解决方案

BepInEx配置管理器:游戏插件配置的终极可视化解决方案

BepInEx配置管理器:游戏插件配置的终极可视化解决方案 【免费下载链接】BepInEx.ConfigurationManager Plugin configuration manager for BepInEx 项目地址: https://gitcode.com/gh_mirrors/be/BepInEx.ConfigurationManager 你是否曾经因为游戏插件的复杂…

2026/8/10 0:00:02 阅读更多 →

周新闻

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁

5分钟告别提取码焦虑:baidupankey如何智能破解百度网盘资源锁 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否曾经在深夜寻找一份重要资料&#x…

2026/8/10 1:05:29 阅读更多 →
如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南

如何快速生成中国车牌图片:Python开源工具完整指南 【免费下载链接】chinese_license_plate_generator 中国车牌生成器 项目地址: https://gitcode.com/gh_mirrors/ch/chinese_license_plate_generator 中国车牌生成器是一个基于Python的开源项目&#xff0c…

2026/8/10 1:05:29 阅读更多 →
收藏!小白程序员轻松入门大模型,从Harness工程开始实践

收藏!小白程序员轻松入门大模型,从Harness工程开始实践

文章强调学习大模型不应只关注模型本身,而应重视模型外的系统搭建,即Harness。提出AgentModelHarness的实用公式,详细介绍Harness的四个层次:持久化层、执行层、控制层和观察与验证层。文章还探讨了上下文工程、工具设计、AGENTS.…

2026/8/10 1:05:29 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/10 17:07:33 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/10 1:05:29 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/10 17:07:33 阅读更多 →