解析编程中不可或缺的基础:深入了解结构体类型

精琢博客,希望可以给大家带来收获~

博主主页:17_Kevin-CSDN博客

收录专栏:《C语言》


引言

在编程中,结构体是一种自定义的数据类型,它允许开发人员将不同类型的数据组合在一起,并为其定义相关属性和行为。结构体提供了一种灵活的方式来表示复杂的数据结构,使得程序设计更加模块化和可读性更高。

结构体类型的声明 

结构的声明
 

声明格式如下:

struct 结构体类型名
{成员名-list;}直接声明变量-list;

结构体变量的声明和使用

下面是一个程序。首先创建了一个结构体类型Stu,里面包括了成员变量name、age、sex和 id。在主函数中创建了结构体变量s,并打印。

结构体变量创建格式:

① 按成员顺序初始化:结构体类型名 + 自定义变量名(+ 初始化内容);

② 按指定顺序初始化:结构体变量名 + 自定义变量名 (+ .成员名);

 变量的使用:结构体变量名 . 成员名

#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;}

结构的不完全声明

在声明结构体类型的时候可以不完全声明,直接在结构体类型后声明变量,这样创建的变量就是一次性变量,之后只能一次性使用。

声明如下:

struct
{int a;char b;float c;
}x;struct
{int a;char b;float c;
}a[20], * p;

结构的⾃引⽤

结构的自引用典型例子就是链表中对节点的定义,用于连续节点连接,具体有关链表的知识可以点击这段蓝字阅读博主另一篇博客。

自引用结构声明格式如下:

struct Node
{int data;struct Node next;
};

自定义结构体

声明格式如下:

格式:typedef + struct 结构体类型名 

        {

                成员变量;

        }自定义类型名;

 示例声明如下:

typedef struct Node
{int data;struct Node* next;
}Node;

结构体内存对⻬(热门考点)

引子

我们经常会用sizeof运算符计算各个变量的字节大小,例如:

#include<stdio.h>int main()
{printf("%d\n", sizeof(int));printf("%d\n", sizeof(short));printf("%d\n", sizeof(long long));return 0;
}

得到结果:

如文所示,我们可以用sizeof来计算各个类型的大小,那么结构体变量计算会得到什么结果呢?

对⻬规则

结构体变量在内存中会遵循结构体对齐规则,对齐规则如下:

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处

2.其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。

   对⻬数=编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。

    VS 中默认的值为
    Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

结构体内存对齐练习

1.非嵌套结构体

#include<stdio.h>int main()
{struct S1{char c1;int i;char c2;};printf("%d\n", sizeof(struct S1));return 0;
}

按照内存对齐规则,从编译器行数从上到下进行内存存储。逐个对比各个成员和VS的默认对齐数8对比,取二者最小对齐数作为对齐数。

根据对齐数从0开始偏移计算每个变量开始存储的内存地址,成员变量要对⻬到对⻬数的整数倍的地址处,如图所示。

最后计算结构体总共大小是需要按照结构体中成员变量的最大对齐数进行对齐,最终结构体大小是最大对齐数的整数倍,产生的浪费空间也要计入总大小。

内存存储图示如下:

2.嵌套结构体

#include<stdio.h>struct S3
{double d;char c;int i;
};int main()
{struct S4{char c1;struct S3 s3;double d;};printf("%d\n", sizeof(struct S4));return 0;
}

计算嵌套结构体的字节大小时对待被嵌套的结构体时,就相当于把嵌套结构体当做结构体的一个成员进行内存对齐。最终计算字节总大小的时候用所有成员中最大对齐数(包括被嵌套结构体中的成员)进行整数倍的计算。

下图即为上述代码的演示图例:

为什么存在内存对⻬?

1. 硬件访问要求: 计算机硬件对于访问内存通常有一定的要求,例如某些硬件可能只能从特定地址开始读取数据,或者只能按照特定的字节长度进行读取。通过内存对齐,可以保证结构体中的字段在内存中按照一定的规则排列,满足硬件访问的要求。

2. 性能优化: 在数据结构中,尤其是在涉及栈这种数据结构时,我们应该尽可能使数据在自然边界上对齐。这样做的原因在于,处理器访问未对齐的内存时需要进行两次内存访问,而对齐的内存访问只需要一次访问。举例来说,如果一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能够保证所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。因此,通过合理地对数据进行内存对齐,我们可以提高程序的执行效率和性能表现。

3. 内存空间利用: 内存对齐可以使数据结构更加紧凑,减少内存空间的浪费。如果结构体中的字段按照对齐规则排列,编译器可以合理地利用内存空间,避免由于未对齐而导致的内存浪费。

4. 平台移植性: 不同的计算机架构可能对内存对齐有不同的要求。合理地处理结构体的内存对齐可以增强程序在不同平台上的移植性,使程序更容易地在不同平台上移植和运行

针对于性能优化,我们可以了解到结构体对齐是为了优化性能,用空间换时间,那么有没有什么办法让我们尽量的减少浪费的空间呢?

我们可以利用结构体对齐的规则,将小的结构体尽量的凑在一起,这样他们会在空间上连续存储,因为对齐数小的和大的之间会存在大对齐数所造成的空间浪费,,所以将小的放一块这样就可以将其中的浪费空间给合理利用起来。

 具体如下代码示例及图示:

struct S1
{char c1;int i;char c2;
};
struct S2
{char c1;char c2;int i;
};

修改默认对齐数

#pragma 这个预处理指令,可以改变编译器的默认对⻬数。

例如,我们要将编译器的默认对齐数修改为1,那么勇以下代码实现:

#pragma pack(1)

如果需要取消修改的默认对齐数,使用以下代码即可实现:

#pragma pack()


 

位段结构体

当我们需要在C或C++中表示一些具有特定位长度的数据时,位段(bit fields)结构体就成为了一种非常有用的工具。位段结构体允许我们将数据按位组织,并且可以更加高效地使用内存空间。

什么是位段结构体?

位段结构体是C和C++中的一种特殊结构,它允许我们定义结构体的成员为特定位长度的字段,从而更为灵活地管理数据。通过位段结构体,我们可以精确地控制每个字段的位数,从而在内存中节约空间。

如何定义位段结构体?

在C和C++中,我们可以使用结构体来定义位段。

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

1. 位段的成员必须是 int、unsigned int 或signed int ,在C99中位段成员的类型也可以
选择其他类型。
2. 位段的成员名后边有⼀个冒号和⼀个数字

下面是一个简单的例子:

struct BitFieldStruct 
{unsigned int flag1 : 1;unsigned int flag2 : 2;unsigned int flag3 : 3;
};

位段的内存分配
 

分配规则:
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;

代码中定义了一个结构体类型S,在main函数中创建S型变量s并初始化为0。重点在于,在已经规定的位段情况下,后面的a,b,c,d赋值后在内存中是如何存储的呢?

图示操作如下:

最后的d由于在第二个字节段中无法存储,所以会直接存到下一个字节中,大小位4比特。


使用位段的注意事项

位段的⼏个成员共有同⼀个字节,这样有些成员的起始位置并不是某个字节的起始位置,那么这些位
置处是没有地址的。内存中每个字节分配⼀个地址,⼀个字节内部的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;
}


 

位段结构体的优势

  1. 节省内存空间:位段结构体可以将多个字段压缩到一个字节中(或者更少),这样可以减少内存使用量。在一些嵌入式系统或需要高效利用内存的场景中,位段结构体可以发挥重要作用。

  2. 更好的可移植性:位段结构体可以帮助开发者更好地处理不同机器上的字节顺序问题和对齐方式。因为位段结构体的字段是按照位来处理的,所以不受机器的字节顺序和对齐方式的影响。

  3. 方便地操作位数据:位段结构体可以方便地处理二进制数据,例如一些硬件寄存器中的位标志。使用位段结构体可以使得代码更加简洁和易读,降低出错的风险。

  4. 更好的兼容性:位段结构体的语法与普通结构体非常相似,因此可以很容易地与其他代码进行交互和集成。此外,C++11标准中还引入了新的标准化位字段类型,称为 std::bitset,可以更加方便地处理位数据。


我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1g0z83rjgi6dj

I'm Kevin, and we'll see you in the next blog

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/543506.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

德人合科技 | 公司办公终端、电脑文件资料 \ 数据透明加密防泄密管理软件系统

天锐绿盾是一款全面的企业级数据安全解决方案&#xff0c;它专注于为企业办公终端、电脑文件资料提供数据透明加密防泄密管理。 首页 德人合科技——www.drhchina.com 这款软件系统的主要功能特点包括&#xff1a; 1. **透明加密技术**&#xff1a; 天锐绿盾采用了透明加密技…

【Java刷题篇】滑动窗口

文章目录 &#x1f4c3;滑动窗口&#x1f4dc;基本概念&#x1f4dc;核心思路 ✍最大连续1的个数 III✍水果成篮 &#x1f4c3;滑动窗口 &#x1f4dc;基本概念 滑动窗口是一种基于双指针的一种思想&#xff0c;两个指针指向的元素之间形成一个窗口。 分类&#xff1a;窗口有…

瑞熙贝通实验室安全培训考试系统

一、系统概述 瑞熙贝通实验室安全培训考试系统是一种基于互联网和人工智能技术的在线考试平台&#xff0c;旨在旨在提供实验室安全教育和考核的全面解决方案。该系统可以帮助实现实验室安全培训考试的在线化、智能化和规范化&#xff0c;提高实验室安全意识和能力&#xff0c;…

​如何使用 ArcGIS Pro 分析爆炸波及建筑

假设在某栋建筑内发生了爆炸&#xff0c;需要根据爆炸的范围分析出来波及的建筑&#xff0c;对于这一需求&#xff0c;我们可以通过ArcGIS Pro来实现&#xff0c;这里为大家介绍一下分析的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载…

HTML实现卷轴动画完整源码附注释

动画效果截图 页面的html结构代码 <!DOCTYPE html> <html> <head lang=

京东云主机+京美建站SaaS版

京美建站SaaS版 京美建站搭建企业网站、小程序、3000精美模板 链接:https://daili.jd.com/s?linkNo57UBX34BZMWGNFYTOCPVUE7SN36CCIPKLTFLPCUCPYBKSYYBIPS2BJ57GP7RACLDHU66X526ZOULMIXL2VN7DT7IHU 京东云主机&#xff0c;安全稳定&#xff0c;性能强劲&#xff0c;新客下单…

修复 error Delete `␍` prettier/prettier 错误

修复 error Delete ␍ prettier/prettier 错误 问题背景报错信息报错原因解决办法修改CRLF----针对单个文件yarn run lint --fix 一键修复&#xff08;官方提供&#xff09; 问题背景 今天在使用 openapi 自动生成前端接口代码的时候&#xff0c;爆了一个类似 eslint 规范的错…

不可变集合

2. 3. 如果键值对超过10个的话 优化之后 要生成不可变的集合直接使用copyof就可以

MySQL大小写敏感、MySQL设置字段大小写敏感

文章目录 一、MySQL大小写敏感规则二、设置数据库及表名大小写敏感2.1、查询库名及表名是否大小写敏感2.2、修改库名及表名大小写敏感 三、MySQL列名大小写不敏感四、lower_case_table_name与校对规则4.1、验证校对规则影响大小写敏感4.1、验证校对规则影响排序 五、设置字段内…

2024 Mazing 3 中文版新功能介绍Windows and macOS

iMazing 3中文版(ios设备管理软件)是一款管理苹果设备的软件&#xff0c; Windows 平台上的一款帮助用户管理 IOS 手机的应用程序。iMazing中文版与苹果设备连接后&#xff0c;可以轻松传输文件&#xff0c;浏览保存信息等&#xff0c;软件功能非常强大&#xff0c;界面简洁明晰…

【考研数学】高等数学总结

文章目录 第一章 极限 函数 连续1.1 极限存在准则及两个重要极限1.1.1 夹逼定理1.1.1.1 数列夹逼定理1.1.1.2函数夹逼定理 1.1.2 两个重要极限1.1.2.1 极限公式11.1.2.1.1 证明1.1.2.1.2 数列的单调有界收敛准则1.1.2.1.2.1 二项式定理1.1.2.1.2.2 证明 1.1.2.2 极限公式21.1.2…

产品推荐 - ALINX XILINX FPGA开发板 Artix-7 XC7A100T-2FGG484I

01开发板介绍 此款开发板采用核心板扩展板的模式&#xff0c;方便用户对核心板的二次开发利用。FPGA使用的是Xilinx公司的ARTIX-7系列的芯片&#xff0c;型号为XC7A100T-2FGG484I。在核心板使用了2片MICRON公司的MT41J256M16HA-125 DDR3芯片&#xff0c;组合成32bit的数据总线…