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

结构体详解

本文是小编巩固自身而作,如有错误,欢迎指出

1.结构体类型声明

在前文,已经讲述过相关问题,这里只进行简单解释

1.1结构声明

struct tag
{member-list;
}variable-list;

如果介绍一本书包括其价格,颜色

struct book
{char color[10];double price;
};

1.2结构体的创建和初始化 

看以下代码即可

#include <stdio.h>
struct Stu
{char name[20];//名字 int age;//年龄 char sex[5];//性别 char id[20];//学号 
};
int main()
{//按照结构体成员的顺序初始化 struct Stu s = { "张三", 20, "男", "20230818001" };printf("name: %s\n", s.name);printf("age : %d\n", s.age);printf("sex : %s\n", s.sex);printf("id : %s\n", s.id);//按照指定的顺序初始化 struct Stu s2 = { .age = 18, .name = "lisi", .id = "20230818002", .sex = 
"⼥" };printf("name: %s\n", s2.name);printf("age : %d\n", s2.age);printf("sex : %s\n", s2.sex);printf("id : %s\n", s2.id);return 0;
}

2.结构体的内存对齐 

这部分内容将是本章重点讲述内容。

我们先看以下代码

struct S1
{char c1;int i;char c2;
};
int main()
{printf("%d\n", sizeof(struct S1));return 0;
}

 

其中struct的内存是怎么计算的呢,这就涉及结构体对齐, 下面详细介绍

内存对齐的原因

硬件访问效率:现代计算机硬件通常以特定的字节数(如2字节、4字节、8字节等)为单位来访问内存。如果数据存储的地址是对齐的,硬件可以更快地读取和写入数据,减少内存访问的次数和时间开销。

对齐规则

  1. 结构体的起始地址:结构体变量的起始地址必须是其最大成员类型大小的整数倍。例如,一个结构体包含一个char(1字节)和一个int(4字节),那么该结构体变量的起始地址必须是4的倍数。
  2. 成员变量的对齐:每个成员变量的存储地址必须是其自身类型大小的整数倍。例如,int类型的成员变量必须存储在4字节对齐的地址上。
  3. 结构体的总大小:结构体的总大小必须是其最大成员类型大小的整数倍。如果需要,编译器会在结构体的末尾填充额外的字节,以满足这个条件。

 

 

其排列可以如图所示

因为其最大对齐数为4,char类型就会浪费三个字节

3.结构体传参

通过上面的学习我们可以知道,结构体的的声明时是会出现内存较大的结构体的,如果直接使用结构体传参,就会开辟大量空间,所以我们可以用地址传参来减少空间的使用

struct S
{int data[1000];int num;
};//结构体地址传参 
void print2(struct S* ps)
{printf("%d\n", ps->num);
}
int main()
{struct S s = { {1,2,3,4}, 1000 };print2(&s); //传地址 return 0;
}

4.结构体实现位段 

4.1什么是位段

位段(bit field)是C语言和C++语言中的一种特殊数据结构,它允许在一个字节或多个字节内精确地分配和使用位。这在节省内存空间和直接操作硬件寄存器等场景中非常有用。

位段的声明和结构是类似的,有两个不同:

1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以 选择其他类型。

2. 位段的成员名后边有⼀个冒号和⼀个数字。

#include<stdio.h>
struct A
{int _a:2;int _b:5;int _c:10;int _d:30;
};
int main()
{printf("%d\n", sizeof(struct A));return 0;
}

 

上述代码其实就是重新将bite位分配在32位环境下int型有32个bite位,其中前三项合起来不过32,共占4个字节

4.2 位段的内存分配

1. 位段的成员可以是 int unsigned int signed int 或者是 char 等类型

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

 3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使⽤位段。

//⼀个例⼦ 
struct S
{char a:3;char b:4;char c:5;char d:4;
};
struct S s = {0};
s.a = 10;
s.b = 12;
s.c = 3;
s.d = 4;
//空间是如何开辟的? 

现在我们来思考空间是怎么开辟的 

我们先看内存中的状况

 如图我们可以看到,内存中存放的是62 03 04,这是为什么呢,下面我们画图解释

 如图所示,当把每一个数从右向左放入内存,即可解释内存的存储

4.3位段使用的注意事项

位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位 置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的bit位是没有地址的。

 所以不能对位段的成员使⽤&操作符,这样就不能使⽤scanf直接给位段的成员输⼊值,只能是先输⼊ 放在⼀个变量中,然后赋值给位段的成员。

 

struct A
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};
int main()
{struct A sa = { 0 };scanf("%d", &sa._b);//这是错误的 //正确的⽰范 int b = 0;scanf("%d", &b);sa._b = b;return 0;
}

今天的分享就到这里了,后续会继续更新,感谢阅读!

相关文章:

  • 《AI大模型应知应会100篇》第27篇:模型温度参数调节:控制创造性与确定性
  • 致远OA——数据回填表单
  • 工业物联网安全网关 —— 安全OTA升级签名验证
  • 回溯算法(3):番外篇
  • 【web服务_负载均衡Nginx】三、Nginx 实践应用与高级配置技巧
  • 上海市计算机学会竞赛平台2023年7月月赛丙组题目解题报告
  • Java中常见的锁synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock
  • 【机器学习】朴素贝叶斯算法:原理剖析与实战应用
  • 深度补全网络:如CSPN++填补稀疏点云的深度信息
  • 修改 <li> 元素小圆点的颜色
  • 不连续数据区间天数累计sql
  • 手机投屏到电视方法
  • MongoDB导出和导入数据
  • 【大疆dji】边缘计算模块在大疆机场中的位置
  • Datawhale AI春训营】AI + 新能源(发电功率预测)Task1
  • nohup的使用
  • 2025年第16届蓝桥杯嵌入式竞赛学习笔记(十四):RTC实时时钟
  • ESB —— 企业集成架构的基石:功能、架构与应用全解析
  • 详细解释浏览器是如何渲染页面的?
  • 国网B接口协议图像数据上报通知接口流程详解以及上报失败原因(电网B接口)
  • 抗美援朝老战士、华西医院精神科学术带头人之一袁德基逝世
  • 人大书报资料中心与中科院文献中心共筑学科融合创新平台
  • 中物联声明:反对美对华物流、海事和造船领域301调查措施
  • 对话地铁读书人|来自大学教授的科普:读书日也是版权日
  • 王毅、董军将主持召开中印尼外长防长“2+2”对话机制首次部长级会议
  • 纪念沈渭滨︱初五沈大大  浓浓师生情