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

C语言:结构体(一)

1、 问题的引入
用计算机去解决现实生活中的一些问题时,需要将现实生活中的物体描述出来。
用计算机语言去描述一个完整的物体 ==> "建模",基本类型不够用

为什么要"建模"?
建模是为了理解事物而对事物进行的一种抽象描述,是对实物的一种无歧义的书面描述。

那么我们程序员建模是怎样建立的?
要解决建模问题的话,需要考虑两点:
a. 问题域(你要描述的现实事物)
b. 解决方案域(实现描述方案,如何去描述)

我们现在假设要用C语言去对一个"学生"进行建模。
也就是说要将"学生"这个现实世界中的物体抽象成计算机中的数据模型,该怎么去描述?
学生:
学号 ==> int num;
姓名 ==> char name[32];
性别 ==> char gender; // 'W' 'M'
年龄 ==> int age;
地址 ==> char addr[100];
身高 ==> float hight;
成绩 ==> double score;
......
那么学生的属性有这么多,而且每一个属性的数据类型都不一样,肯定不能用基本类型或者数组类型来完整描述,
那么怎么才能将这些物体的属性组合到一个类型中去,用来表示学生? ==> 结构体

2、 结构体 struct
C语言中提供struct关键字,用来自定义一种组合数据类型

1) 结构体类型怎么定义?
struct 结构体类型名
{
成员类型1 成员变量名1;
成员类型2 成员变量名2;
成员类型3 成员变量名3;
......
成员类型n 成员变量名n;
};
结构体类型是由多个成员组成的,而且每一个成员变量都有自己的类型(只要是合法的C语言类型都是可以的),当然,不同
的成员类型可以相同的,但是成员名不能相同。

"结构体类型名":也是C语言标识符的一种,意味着要符合C语言标识符的定义
struct 结构体类型名 ==> 你定义的新类型的名字

例如:
struct student ==> 新类型完整的名字包括struct

"成员类型1、成员类型2、成员类型3、...、成员类型n":
只要是合法的C语言类型(基本类型、构造类型、指针类型)都是可以的

"成员变量名1、成员变量名2、成员变量名3、...、成员变量名n":
要符合C语言关于标识符的规定。

结构体的变量
在定义了一个新的类型时,第一个就要讨论如何定义新类型的变量:
类型名 变量名{= 初始值};

结构体类型名 变量名;

例如:
struct student s;
s 是一个结构体变量,里面会有 一个int类型的成员num,一个char[32]类型的成员name ...
那么这些成员在内存中时如何分布的呢?

2) 结构体成员的内存分布
1、结构体类型定义的变量所占空间是各成员变量所占空间之和(可能会有填充),有填充是因为 "按字节对齐" 的规则。
2、结构体内部各成员变量是按照它们定义时出现的顺序,依次保存。

例子:

其运行结果为:

因为在32位操作系统中,最多最多是按4字节对齐的,意思就是哪怕结构体中最大基本类型的变量的长度超过了4个字节,也是按照
4字节一单元来算的,而64位操作系统还是根据其最大的基本类型的长度来确定字节对齐的,如果最长数据为8个字节,则按8字节对
齐,如果最长数据为4字节,则按4字节对齐。



为了CPU的访问效率,一般会要求,任何对象的地址都是对齐的。

字节对齐:就是 变量存储的地址是变量的有效字节对齐值的整数倍
address % 最终有效字节对齐值 == 0

按字节对齐是计算机内存管理中数据存储的规则:数据在内存中的起始地址必须是其"对齐值"的整数倍,这么做是为了提高
CPU的内存访问效率。

CPU访问内存时并非是逐个字节读取的,而是按"块"读取(如32位CPU一次读取4个字节,64位CPU一次读取8个字节),如果数据存储时
不遵循按字节对齐的规则,可能导致CPU需要多次读取才能获取完整的数据,大幅降低读取效率。

例子:
32位CPU读取4字节int类型的数据时,若数据起始地址是4的倍数(如0x0004),那么一次就能读完
若数据起始地址不是4的倍数(如0x003),CPU就需要先读取 0x0000-0x0003 ,再读取 0x0004-0x0007,
最后先处理两部分数据,然后再拼接成目标数据,导致效率大大降低。

对齐值的规则
不同数据类型的"对齐值"(即起始地址需要满足的倍数)是由编译器和系统共同决定的

在32位系统中,变量的字节对齐值:
char 为1字节对齐
short 为2字节对齐
int/float/double 为4字节对齐

在64位系统中,变量的字节对齐值:
char 为1字节对齐
short 为2字节对齐
int/float 为4字节对齐
double 为8字节对齐

其实字节对齐的细节和具体的实现是与编译器和操作系统相关,但是一般而言,满足以下规则:
1、 结构体变量的首地址能够被其最宽基本类型的成员变量的字节对齐值大小所整除。
2、 结构体的每个成员变量的地址对于结构体首地址的偏移量都是成员大小或者成员
(比如说数组、结构体等)的子成员大小的整数倍。
3、 结构体的总大小为结构体最宽基本类型的成员大小的整数倍。

3) 结构体变量的引用
结构体内部成员变量的引用
1、 .(域操作符)
作用:用来取结构体变量的某个子成员
语法:结构体变量名.成员变量名

==>能够去访问结构体变量内部的成员变量

代码示例:

分别输入xiaocheng和xiaoyuan,运行结果为:

对于普通变量而言,它有地址,且可以通过指针指向该变量的地址来访问该变量的内存空间,
同样的我们也可以用一个指针去指向一个结构体变量,然后通过该指针去访问该结构体变量的内存空间:
struct student *p = &stu1; 自解:定义指针p为取stu1的地址

2、 ->(分量运算符)
作用:用来取指针所指向的结构体变量的某个子成员
语法:结构体指针变量名->成员变量名

例子:

输入xiaocheng后,其运行结果为:

3、 (*结构体指针变量名).成员变量名
(*p).age
(*p).num

4、 (&结构体变量名)->成员变量名
(&stu1)->age
(&stu1)->num

所以一个结构体变量可以通过多种方式引用它的成员变量:
struct student stu;
struct student *p = &stu;

stu.age;
(&stu)->age;
p->age;
(*p).age;

4) 在定义类型的同时,可以定义结构体变量:
struct 结构体类型名
{
成员类型1 成员变量名1;
成员类型2 成员变量名2;
成员类型3 成员变量名3;
......
成员类型n 成员变量名n;
}结构体变量名;

struct Point
{
int x;
int y;
} p1, *p2;
struct point *p = (struct point*)=malloc(sizeof(struct point*))
以上代码定义了一个struct Point类型,这种类型的变量有两个整型的成员变量,
同时定义了一个结构体类型的普通变量和指针变量。

例子:

输入xiaocheng后,其运行结果为:

5) 动态创建结构体变量
int *a = (int *)malloc(sizeof(int));

结构体类型名 *结构体指针变量名 = (结构体类型名 *)malloc(sizeof(结构体类型名)); 重点:右边的第二个括号没有*

例如:

其运行结果为:

6) 把结构体变量作为函数参数进行传参
可以把结构体变量的值整体传给一个函数
例如:struct Point struct_print(struct Point p1);

可以把结构体变量的地址传给一个函数
例如:struct Point *struct_print(struct Point *p1);

7) 结构体数组
结构体类型名 数组名[元素个数]{= {初始化列表}};
结构体类型名 *结构体类型指针名 = (结构体类型名 *)malloc(元素个数 * sizeof(结构体类型名));
例如:

其运行结果为:

http://www.rkmt.cn/news/1454887.html

相关文章:

  • 从 CodeBuddy 到马维斯:不得不说国内大厂执行力还是强
  • 终极指南:如何在React项目中快速集成Markdown渲染功能
  • Nintendo Switch游戏文件终极管理神器:NSC_BUILDER完整指南
  • 双旋转太阳能摆:极简电路实现微安级功耗的准永动艺术装置
  • 如何用3步将B站缓存视频永久保存为通用MP4格式
  • HyDE 假设文档嵌入:提升 RAG 检索命中率的黑魔法
  • 别再手动造数据了!用MQTTX脚本+定时发送,5分钟搞定物联网温湿度模拟测试
  • 2026年6月忻州贵金属回收权威门店排行 TOP5 黄金 + 铂金 + 白银回收 附电话地址 - 中业金奢再生回收中心
  • Gopher360:如何用游戏手柄5分钟搞定客厅电脑控制的终极指南
  • 【数据库数据恢复】Oracle数据库各类故障恢复方法与注意事项
  • Windows 11终极瘦身方案:免费开源工具让你的电脑重获新生
  • Claude 母公司冲刺 IPO:大模型竞争正在从“模型能力”走向“工程化落地”
  • XTOOL朗仁新能源维修设备打造一站式解决方案
  • Axure RP 11 中文语言包终极配置指南:3步打造原生中文体验
  • NBTExplorer:开启我的世界数据编辑的新纪元,成为游戏世界的真正创造者
  • OpCore-Simplify终极指南:30分钟完成OpenCore EFI配置,成功率92.3%
  • Windows端口老被占?可能是这些后台进程在捣鬼(附排查与预防指南)
  • Betaflight Configurator:3步掌握无人机飞行控制配置的完整指南
  • 3分钟解锁RPG Maker加密资源:从黑盒到开源编辑的完整方案
  • 君南信息三效系统解决方案:打造数智驱动的运营新范式
  • 电子负载的作用
  • Diff Checker:三分钟掌握高效文本差异对比的终极解决方案
  • NarratoAI终极指南:开源AI视频解说工具快速入门
  • 别再只盯着损失函数了:聊聊机器学习里那个更“物理”的能量函数(附Python小例子)
  • OpCore-Simplify黑苹果配置神器:让OpenCore EFI配置从复杂到简单的革命性工具
  • 目前靠谱的青铜器公司哪家强
  • 075、ONNX Runtime 推理加速:使用 CUDA/TensorRT/RoCM EP 提供者加速 YOLO
  • 你的AI图像质量评分师:如何用深度学习让计算机“看懂“好照片?
  • 从压力开关到LED电路:STEAM教育中的电动拥抱玩偶制作指南
  • 谷歌排名优化需要多长时间见效?认清SEO代运营骗局的2个时间点