马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、结构体范例的声明
1、结构体的声明
- 结构体的声明:
- struct tag
- {
- member-list
- };
复制代码 2、结构体变量的创建和初始化
创建一个简单的学生信息结构体
- struct student
- {
- char name[20];
- int age;
- int score;
- };
复制代码 结构体默认初始化的顺序是结构体中创建变量的顺序。
初始化结构体:
- struct student
- {
- char name[20];
- int age;
- int score;
- }s1, s2 = {"李华",18,88}; //第一种初始化
- struct student s3 = { "小明",20,100 }; //第二种初始化
- int main()
- {
- struct student s4 = { "张三",15,70 }; //第三种初始化
- struct student s5 = { .score = 99,.name = "小红",.age = 22 }; //第四种初始化
- return 0;
- }
复制代码
3、特殊声明
匿名结构体
- struct
- {
- int a;
- char b;
- float c;
- }x,*p;
复制代码 匿名结构体只允许利用一次,p=&a黑白法请求
4、结构体的自引用
结构体是可以进行自引用的
- 错误的自引用:
- struct stu
- {
- int a;
- struct stu next;
- };
- 正确的自引用:
- struct stu
- {
- int a;
- struct stu* next;
- };
复制代码 5、typedef重定名结构体
- typedef struct Node
- {
- int data;
- struct Node* next;
- }Node; //结构体命名为Node
复制代码 二、结构体内存对⻬
1、对齐规则
把握结构体的对齐规则:
- 结构体中第一个变量首对齐地址是偏移量为0的地址处。
- 其他成员的对齐变量是范例的整数倍数的地址处。vs默认对齐量为8,linux中gcc没用对齐数,对齐数就是自身大小
- 结构体的总大小为最大对齐数
- 对于嵌套结构体,嵌套结构中对齐量是结构体中最大的一个变量整数倍数地址处,而竣事时是嵌套结构体的整数倍数
如盘算int 对齐数 4 8 4 int范例的大小对比默认值大小,谁小选谁是对齐数
- //练习1
- struct S1
- {
- char c1;
- int i;
- char c2;
- };
- printf("%d\n", sizeof(struct S1));
- //练习2
- struct S2
- {
- char c1;
- char c2;
- int i;
- };
- printf("%d\n", sizeof(struct S2));
- //练习3
- struct S3
- {
- double d;
- char c;
- int i;
- };
- printf("%d\n", sizeof(struct S3));
- //练习4-结构体嵌套问题
- struct S4
- {
- char c1;
- struct S3 s3;
- double d;
- };
- printf("%d\n", sizeof(struct S4));
复制代码
在以上例题中,我们发现结构体中开辟的空间有许多空间被浪费了,以是在创建范例时,需要合理的排序
在例题1与例题2中,创建的范例是一样的,就由于范例创建的顺序不一样,导致占用内存不一样。
尽量使变量小的范例排在前面
2、为什么存在内存对齐
1、平台移植问题:不是全部的硬件平台都能访问任意地址上的任意数据
2、性能问题:假如没用地址对齐,处理器需要作两次的内存访问,而对齐的内存只需要访问一次
总结来说:拿空间换时间
3、修改默认对齐数
通过利用#pragma这个预处理指令,可以改变编译器的默认对齐数
- #pragma pack(4)//设置对齐数变为4
- struct stu
- {
- char a;
- int b;
- char d;
- double c;
- };
- #pragma pack()//取消设置的对齐数,还原默认
- int main()
- {
- printf("%zd\n", sizeof(struct stu));
- }
复制代码
三、结构体传参
- struct stu
- {
- char name[10];
- int age;
- };
- struct stu s1 = { "xiaoming",28 };
- void print1(struct stu s1)
- {
- printf("%d,%s\n", s1.age, s1.name);
- }
- void print2(struct stu* s1)
- {
- printf("%d,%s\n", s1->age, s1->name);
- }
- int main()
- {
- print1(s1); //传值调用
- print2(&s1); //传址调用
- return 0;
- }
复制代码 输出:
结构体可以利用传值也可以利用传址,优先选用传址调用,如许不需要开辟新的空间,可以大大提高代码的运行效率。
四、结构体实现位段
1、什么是位段
位端可以限制结构体中创建变量占用内存的大小
- 利用位段时,成名必须是unsigend int,int,sigent int,在c99中其他成员可以利用位段
- 位段的创建在成员名后面加上一个冒号跟一个数字。
比如:
- struct stu
- {
- int _a : 4;
- int _b : 2;
- int _c : 1;
- int _d : 30;
- };
复制代码 2、位段的内存分配
- 位段的成员可以是int,unsigent int ,signet int,char范例
- 位段上的空间是以四个字节跟一个字节进行开辟空间的
- 位段无法跨平台利用
- struct stu
- {
- int _a : 4;
- int _b : 10;
- int _c : 1;
- int _d : 20;
- };
- int main()
- {
- printf("%zd\n", sizeof(struct stu));
- return;
- }
复制代码 输出:
假如没用位段,那么4个int范例的字节大小位12
位段是如何开辟空间的,如下:
3、位段的跨平台问题
1、int位段是被当成有符号位还是无符号位是不确定的
2、位段中最大数是不确定的(有16位机器,假如设置段位超过16比特,那么就会出问题,32位机器同意也是)
3、内存是从左到右分配,还是从右到左分配是不确定的(vs是从右到左分配)
4、当一个结构体包罗两个位段时,第二个位段成员比较大,无法容纳第一个尾端剩余空间的时间,是否会舍弃剩余空间,这是不确定的。
总结:位段可以很好的节流空间,但存在跨平台问题
4、位段的应⽤
下图是⽹络协议中,IP数据报的格式,我们可以看到其中很多的属性只需要⼏个bit位就能描述,这⾥使⽤位段,可以或许实现想要的结果,也节流了空间,如许⽹络传输的数据报⼤⼩也会较⼩⼀些,对⽹络的畅通是有资助的。
5、位段使⽤的留意事项
无法获取比特位的地址。
无法直接利用scanf来输入位段,但是可以赋值位段
- struct stu
- {
- int _a : 4;
- int _b : 10;
- int _c : 1;
- int _d : 20;
- };
- int main()
- {
- struct stu s = { 0 };
- int n = 0;
- scanf("%d", &n);
- s._a = n;
- return;
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |