C语言探索之旅:深入理解结构体的奥秘

news2025/7/23 6:38:54

目录

引言

一、什么是结构体?

二、结构体类型的声明和初始化

1、结构体的声明

2、结构体的初始化

3、结构体的特殊声明

4、结构体的自引用

5、结构体的重命名

三、结构体的内存对齐

1、对齐规则

2、为什么存在内存对齐?

3、修改默认对齐数

三、结构体传参

四、结构体的位段

1、什么是位段?

2、位段的内存分配

3、位段的跨平台问题

4、注意事项

五、结语


引言

在C语言的世界里,结构体是一项强大的工具,它让我们能够将多种不同类型的数据组合在一起,构建复杂的数据模型。无论是模拟现实中的实体对象,还是组织程序中的多信息数据,结构体都扮演着不可或缺的角色。本文将带你从基础入门,逐步探索结构体的定义、使用方法以及在实际开发中的应用技巧,帮助你更高效地掌握C语言的核心知识。

一、什么是结构体?

首先来回顾一下数组的定义:数组就是相同类型元素的集合。但是,实际中描述某个物体的数据绝大部分都是不同类型,这时候就需要一个新的东西来把这些数据集合起来:结构体

结构体就是存放不同类型的数据的集合。

二、结构体类型的声明和初始化

1、结构体的声明

struct name
{
	int member1;
	double member2;
	char member3;
	//……
};//分号不能丢掉!

struct 是语法要求 ,

name为结构体的名字,自己可以随便起名,

大括号里的 member 为结构体的成员,

最后的分号不能丢掉!

2、结构体的初始化

要想初始化结构体,我们首先要声明一个结构体:

struct student
{
	char name[20]; //学生的姓名
	int mumber;    //学生的学号
	double score;  //学生的平均分
};

如上代码,我创建了一个学生的结构体,包含了姓名,学号和平均分,下面就要创建一个结构体变量:

int main()
{
	struct student n1;
	return 0;
}

n1 就是一个结构体变量,对其初始化跟普通的变量一致:

struct student n1 = {"sichenglang" ,5438438 , 48.38};

3、结构体的特殊声明

有特殊结构体是可以匿名的:

struct 
{
	char name[20]; //学生的姓名
	int mumber;    //学生的学号
	double score;  //学生的平均分
}n1; //创建了一个结构体变量 n1

但是,匿名结构体只能使用一次,即创建一个变量 n1。

那么如果再次创建一个元素相同的匿名变量呢?

struct student
{
	char name[20]; //学生的姓名
	int mumber;    //学生的学号
	double score;  //学生的平均分
}n2;

编译器认为,这两个结构体是两种结构体,如果你要 n1 = n2 ; 那么编译器就会发出警告!

4、结构体的自引用

结构体内不可能嵌套它本身,如同下面的代码:

struct tong
{
   int ma;
   struct tong si;
};

这个代码编译器会发出警告!因为 sizeof(struct tong) = sizeof(struct tong) + sizeof(int)  显然这是不可能的

因此,结构体自引用只能以指针的形式:

struct tong
{
   int a;
   struct tong* si;
};

其实这玩意就是单链表的一个元素

5、结构体的重命名

用 typedef 来给结构体重命名:

typedef struct tong
{
	int si;
	char lang;
}ma;

这里我们可以在结构体声明的时候就顺带重命名了

struct tong n1;
ma n1;

以上两行代码是等价的

三、结构体的内存对齐

先来看看以下代码:

struct s1
{
	char c1;
	char c2;
	int n;
};

struct s2
{
	char c1;
	int n;
	char c2;
};

int main()
{
	printf("%zu\n" ,sizeof(struct s1));
	printf("%zu\n" ,sizeof(struct s2));
	return 0;
}

结果是:

这就是由结构体的内存对齐造成的

1、对齐规则

(1)、第一个成员对齐到结构体变量起始位置偏移量为0的位置

(2)、从第二个成员开始,都要对齐到某个对齐数的整数倍的位置

   对齐数 = 编译器默认对齐数与该成员大小的较小值

   VS的默认对齐数为8 

(3)、结构体总的大小为最大对齐数的整数倍 (含嵌套里面的结构体的对齐数)

下面是结构体s1 和 s2 对齐结构图

最终的大小为4的倍数就是8

而现在,从 0 ~8 共9个字节,我们要求的是最大偏移量 4 的整数倍,那么就只有12了

2、为什么存在内存对齐?

平台原因,性能原因

总的来说,是用空间换取时间的做法

3、修改默认对齐数

用 #pragma 这个指令,具体看下面的例子:

#pragma pack(1) //设置数一般都是2的几次方
struct s1
{
	char c1;
	int n;
	char c2;
};
#pragma pcak() //还原默认对齐数

三、结构体传参

函数传参的时候,参数是需要压栈,会耗费时间和空间,如果传递的结构体过大,那么时间和空间的耗费就比较大,导致性能下降

结论:结构体传参,尽量传地址

 

四、结构体的位段

1、什么是位段?

这里直接举个例子说明:

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};

冒号后面的数字比啊是这个成员要占用的比特位的数量,比如a只占两个比特位

位段的成员必须是 int ,unsigned int ,signed int 类型

2、位段的内存分配

位段的空间上是按照需要以4个字节(int)或者 1个字节(char)来开辟空间的

例如这个位段:

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
//sizeof(struct S) = 3
它在内存中是这样分配的:

3、位段的跨平台问题

位段中的最大位数目不确定;
位段中成员在内存中从左向右分配还是从右向左分配不确定
结论: 跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。

4、注意事项

不能对位段成员取地址,也不能用scanf对位段成员输入,但可以
int b = 0;
scanf("%d" ,&b);
S._b = b;

五、结语

结构体作为C语言中实现复杂数据管理的重要机制,理解并善用它,能够极大地提升你的程序设计水平。从定义到操作,从简单到复杂,逐步掌握结构体的使用技巧,你将在C语言的编程世界中游刃有余。希望这篇文章能为你的学习提供有价值的启示,让你在未来的开发道路上更加自信和高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2401056.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

经典算法回顾之最小生成树

最小生成树(Minimum Spanning Tree,简称MST)是图论中的一个重要概念,主要用于解决加权无向图中连接所有顶点且总权重最小的树结构问题。本文对两种经典的算法即Prim算法和Kruskal算法进行回顾,并对后者的正确性给出简单…

Ubuntu下实现nginx反向代理

1. 多个ngx实例安装 脚本已经在deepseek的指导下完成啦! deepseek写的脚本支持ubuntu/centos两种系统。 ins_prefix"/usr/local/" makefile_gen() {ngx$1 ngx_log_dir"/var/log/"$ngx"/"ngx_temp_path"/var/temp/"${ngx}…

c++ QicsTable使用实例

效果图&#xff1a; #include <QicsTable.h> #include <QicsDataModelDefault.h> #include <QVBoxLayout> Demo1::Demo1(QWidget *parent) : QWidget(parent) { ui.setupUi(this); const int numRows 10; const int numCols 5; // create th…

在WordPress上添加隐私政策页面

在如今的互联网时代&#xff0c;保护用户隐私已经成为每个网站管理员的责任。隐私政策不仅是法律要求&#xff0c;还能提高用户对网站的信任。本文将介绍两种常用方法&#xff0c;帮助你在WordPress上轻松创建并发布隐私政策页面。这些方法简单易行&#xff0c;符合中国用户的阅…

阿里云ACP云计算备考笔记 (3)——云服务器ECS

目录 第一章 整体概览 第二章 ECS简介 1、产品概念 2、ECS对比本地IDC 3、BGP机房优势 第三章 ECS实例 1、实例规格族 2、实例系列 3、应用场景推荐选型 4、实例状态 5、创建实例 ① 完成基础配置 ② 完成网络和安全组配置 ③ 完成管理配置和高级选项 ④ 确认下单…

从零开始:用Tkinter打造你的第一个Python桌面应用

目录 一、界面搭建&#xff1a;像搭积木一样组合控件 二、菜单系统&#xff1a;给应用装上“控制中枢” 三、事件驱动&#xff1a;让界面“活”起来 四、进阶技巧&#xff1a;打造专业级体验 五、部署发布&#xff1a;让作品触手可及 六、学习路径建议 在Python生态中&am…

Web开发主流前后端框架总结

&#x1f5a5; 一、前端主流框架 前端框架的核心是提升用户界面开发效率&#xff0c;实现高交互性应用。当前三大主流框架各有侧重&#xff1a; React (Meta/Facebook) 核心特点&#xff1a;采用组件化架构与虚拟DOM技术&#xff08;减少真实DOM操作&#xff0c;优化渲染性能&…

GlobalSign、DigiCert、Sectigo三种SSL安全证书有什么区别?

‌GlobalSign、DigiCert和Sectigo是三家知名的SSL证书颁发机构&#xff0c;其产品在安全性、功能、价格和适用场景上存在一定差异。选择SSL证书就像为你的网站挑选最合身的“安全盔甲”&#xff0c;核心是匹配你的实际需求&#xff0c;避免过度配置或防护不足。 一、核心特点对…

力扣面试150题--二叉搜索树中第k小的元素

Day 58 题目描述 思路 直接采取中序遍历&#xff0c;不过我们将k参与到中序遍历中&#xff0c;遍历到第k个元素就结束 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* …

SQL Server Agent 不可用怎么办?

在 SQL Server Management Studio (SSMS) 中&#xff0c;SQL Server Agent 通常位于对象资源管理器&#xff08;Object Explorer&#xff09;的树形结构中&#xff0c;作为 SQL Server 实例的子节点。以下是详细说明和可能的原因&#xff1a; 1. SQL Server Agent 的位置 默认路…

css-塞贝尔曲线

文章目录 1、定义2、使用和解释 1、定义 cubic-bezier() 函数定义了一个贝塞尔曲线(Cubic Bezier)语法&#xff1a;cubic-bezier(x1,y1,x2,y2) 2、使用和解释 x1,y1,x2,y2&#xff0c;表示两个点的坐标P1(x1,y1),P2(x2,y2)将以一条直线放在范围只有 1 的坐标轴中&#xff0c;并…

docker使用proxy拉取镜像

前提条件&#xff0c;宿主机可以访问docker hub 虚拟机上telnet 宿主机7890能正常访问 下面的才是关键&#xff0c;上面部分自己想办法~ 3. 编辑 /etc/docker/daemon.json {"proxies": {"http-proxy": "http://192.168.100.1:7890","ht…

服务端定时器的学习(一)

一、定时器 1、定时器是什么&#xff1f; 定时器不仅存在于硬件领域&#xff0c;在软件层面&#xff08;客户端、网页和服务端&#xff09;也普遍应用&#xff0c;核心功能都是高效管理大量延时任务。不同应用场景下&#xff0c;其实现方式和使用方法有所差异。 2、定时器解…

Modbus转EtherNET IP网关开启节能改造新范式

在现代工业生产和能源管理中&#xff0c;无锡耐特森Modbus转EtherNET IP网关MCN-EN3001发挥着至关重要的作用。通过将传统的串行通信协议Modbus转换为基于以太网的EtherNET IP协议&#xff0c;这种网关设备不仅提高了数据传输的效率&#xff0c;而且为能源管理和控制系统的现代…

C#入门学习笔记 #7(传值/引用/输出/数组/具名/可选参数、扩展方法(this参数))

欢迎进入这篇文章,文章内容为学习C#过程中做的笔记,可能有些内容的逻辑衔接不是很连贯,但还是决定分享出来,由衷的希望可以帮助到你。 笔记内容会持续更新~~ 本篇介绍各种参数,参数本质上属于方法的一部分,所以本篇算是对方法更深度的学习。本章难度较大... 传值参数 …

【DeepSeek】【Dify】:用 Dify 对话流+标题关键词注入,让 RAG 准确率飞跃

1 构建对话流处理数据 初始准备 文章大纲摘要 数据标注和清洗 代码执行 特别注解 2 对话流测试 准备工作 大纲生成 清洗片段 整合分段 3 构建知识库 构建 召回测试 4 实战应用测试 关键词提取 智能总结 测试 1 构建对话流处理数据 初始准备 构建对话变量 用…

yFiles:专业级图可视化终极解决方案

以下是对yFiles的详细介绍,结合其定义、功能、技术特点、应用场景及行业评价等多维度分析: 一、yFiles的定义与核心定位 yFiles是由德国公司yWorks GmbH开发的 动态图与网络可视化软件开发工具包(SDK) ,专注于帮助用户将复杂数据转化为交互式图表。其核心价值在于提供跨平…

VSCode 工作区配置文件通用模板创建脚本

下面是分别使用 Python 和 Shell&#xff08;Bash&#xff09;脚本 自动生成 .vscode 文件夹及其三个核心配置文件&#xff08;settings.json、tasks.json、launch.json&#xff09;的完整示例。 你可以选择你熟悉的语言版本来使用&#xff0c;非常适合自动化项目初始化流程。…

echarts显示/隐藏标签的同时,始终显示饼图中间文字

显示标签的同时&#xff0c;始终显示饼图中间文字 let _data this.chartData.slice(1).map((item) > ({name: item.productName,value: Number(item.stock), })); this.chart.setOption({tooltip: {trigger: item,},graphic: { // 重点在这里&#xff08;显示饼图中间文字&…

SpringBoot关于文件上传超出大小限制--设置了全局异常但是没有正常捕获的情况+捕获后没有正常响应返给前端

项目背景 一个档案管理系统&#xff0c;在上传比较大的文件时由于系统设置的文件大小受限导致文件上传不了&#xff0c;这时候设置的异常捕捉未能正常报错导致前端页面一直在转圈&#xff0c;实际上后端早已校验完成。 全局异常类设置的捕捉 添加了ControllerAdvice以及RestCon…