当前位置: 首页 > article >正文

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

目录

引言

一、什么是结构体?

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

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.lryc.cn/news/2401056.html

相关文章:

  • uniapp 开发企业微信小程序,如何区别生产环境和测试环境?来处理不同的服务请求
  • Dockerfile常用指令介绍
  • Docker 容器化:核心技术原理与实践
  • 不确定性分析在LEAP能源-环境系统建模中的整合与应用
  • 经典算法回顾之最小生成树
  • Ubuntu下实现nginx反向代理
  • c++ QicsTable使用实例
  • 在WordPress上添加隐私政策页面
  • 二维 根据矩阵变换计算镜像旋转角度
  • 你工作中涉及的安全方面的测试有哪些怎么回答
  • 阿里云ACP云计算备考笔记 (3)——云服务器ECS
  • Eigen实现非线性最小二乘拟合 + Gauss-Newton算法
  • 区块链技术:原理、应用与发展趋势
  • 从零开始:用Tkinter打造你的第一个Python桌面应用
  • Web开发主流前后端框架总结
  • Java Spring Boot 自定义注解详解与实践
  • GlobalSign、DigiCert、Sectigo三种SSL安全证书有什么区别?
  • 力扣面试150题--二叉搜索树中第k小的元素
  • SQL Server Agent 不可用怎么办?
  • css-塞贝尔曲线
  • Java并发编程哲学系列汇总
  • docker使用proxy拉取镜像
  • 服务端定时器的学习(一)
  • 【前端】vue 防抖和节流
  • Modbus转EtherNET IP网关开启节能改造新范式
  • Android高级开发第四篇 - JNI性能优化技巧和高级调试方法
  • 【PCB工艺】绘制原理图 + PCB设计大纲:最小核心板STM32F103ZET6
  • C#入门学习笔记 #7(传值/引用/输出/数组/具名/可选参数、扩展方法(this参数))
  • 【DeepSeek】【Dify】:用 Dify 对话流+标题关键词注入,让 RAG 准确率飞跃
  • DELETE 与 TRUNCATE、DROP 的区别