目录
引言
在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、注意事项
int b = 0;
scanf("%d" ,&b);
S._b = b;
五、结语
结构体作为C语言中实现复杂数据管理的重要机制,理解并善用它,能够极大地提升你的程序设计水平。从定义到操作,从简单到复杂,逐步掌握结构体的使用技巧,你将在C语言的编程世界中游刃有余。希望这篇文章能为你的学习提供有价值的启示,让你在未来的开发道路上更加自信和高效。