结构体的详解

本文详细介绍了C语言中结构体的概念、定义与初始化方法,并深入探讨了结构体成员的访问方式,包括直接访问与指针访问。此外,还讨论了结构体对齐规则及其对内存分配的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结构体的初始化

结构体:为了解决C语言中基本数据类型单一的问题而应运而生的一种组合类型的数据,可以有基本类型的操作,解决了C语言不能处理复杂数据类型的问题。

结构体的定义:

    struct s
    {
        int a;
        int b[20];
        char c;
        char *d;
        ......
        可以无限的叠加,只要是实际需要或者内心需要。
    };//结构体的定义,struct为关键字,关键字之后为用户定义的结构体的名称,在结构体对的最末尾,必须添加结构体定义的结束标志(;)分号。

结构体的成员变量的访问。
定义一个结构体

struct s
{
    int a;
    char b;
}s = {4,'a'};//定义结构体的同时,定义了一个结构体的变量,之后,对这个结构体变量进行赋值。

/*可以直接访问结构体的各个成员变量,也可以使用指针来间接的指向结构体的各成员变量。
直接访问时,通过结构体的运算符号(.)来访问。
例如: s.a表示结构体的a成员。s.b表示结构体的b成员。
指针访问时,通过各个成员不同的的指针类型来访问。
int *a1 = (int *)((long)&s); 表示结构体的a成员,a成员的类型为int型,所以采用指针类型来表示。因为64位环境下地址为8位的数据类型,所以采用long(long为8位)来强制类型转换,最后通过每一个元素在结构体中的偏移量来计算每一个元素的值的类型。最后遍历指针,指向最后的值。*/

对应的除了普通的结构体变量,结构体还有指针,结构体指针。当结构体指针指向了一个具体的结构体的时候,结构体指针如何调用指针所指向的变量。于是我们引入了一个新的运算符(->)引用时对应的
例如 :
s->a//表示结构体指针访问结构体指针所指结构体的成员a
结构体指针更多的应用于对于结构体操作的函数之中,因为结构体的成员不定,一味地用赋值的方法,会造成内存的过多的浪费,及其他的内存浪费的现象。所以指针的出现,极大地省了内存的使用。

结构体的对齐。

对齐规则,使用者定义一个结构体的变量之后,编译器会对结构体整体进行一次扫描,扫描之后,编译器找到了一个结构体成员变量,该基础成员变量占用的字节数最多,以该字节数为该结构体的对齐字节数。下面来一个例子。

struct data
{
    char a;
    short b;
    int c;
    long d;
};
/*
该结构体,long是占用字节数最多的一个基础类型,为8字节。
char 类型占用了一个字节,之后放short,编译器发现前面的4个字节只剩下了3个字节,但是前面的char只用了一个字节,但是short不会从char之后直接存储,而是在char占用的一个字节之后再来一个空的字节占用,short再放入空间中,此时从char开始的4个字节全部占用完,int进来之后,发现前面对的元素占用了4字节(int类型的大小)的整数倍,int就直接放在了第五个字节的地方。int 占用了空间之后,long又来了,long发现前面的占用了8字节的整数倍(long类型占用空间的整数倍),所以long也直接放在了int的后边。该结构体占用了16字节额大小。最后一步,结构体各 成员变量占用完之后,如果没有占用最大基础类型的整数倍,补齐到整数倍,否则,直接完成结构体占用内存处理的操作*/
/*
    先扫描,找最大占用字节的类型。
    第一个随便放。
    后放的每一个依次看前一个数据类型放完之后所占用的空间是否是自己的整数倍,是的话直接放。不是的话,补齐时候再放。
    所有成员放完之后。看占用内存呢是否为,最大占用字节的类型的整数倍,是的话,计算完成,否则,补齐到整数倍的最小值。
*/

结构体的对齐指令

#pragma pack(n) (1、2、4、8、.....)
#pragma pack()
联合使用,来获得空间上的节省,但是计算机的运行效率会减少。
而且n的数值只能为2的n次方
特殊的是,当对齐指令中的n超过了结构体扫描获得的的最大字节类型。按照最大细节类型的对齐规则对齐。否则,按照n的对齐规则来对齐。
就是两者取小的数值来制定对齐规则

位字段

为字段只用于结构体,而且结构体的各个成员必须是整形,或者是无符号整形。

struct data1
{
        unsigned a : 1;     // 1就是一个bit,范围:0~1
        int : 31;           // 无名字段,不可访问,只是占位
        unsigned b : 2;     // 2就是er个bit,范围:0~3
        unsigned c : 2;     // 28位 
}s1;

struct data2
{
        unsigned a : 1;     // 1就是一个bit,范围:0~1
        int : 0;            // 0字段,不可访问,只是占位整个字剩下的位,全部写0
        unsigned b : 30;    // 2就是er个bit,范围:0~3
        int : 0;
        unsigned c : 2;     // 28位 
}s2;

//位字段:下一个字段不够在剩余的bit存放时,必须另起一个字。字段不能跨字。
struct data3
{
        int a : 2;
        int b : 32;
}s3;
位字段的对齐规则。
第一个先放,第二个放的时候判断剩余空间(4字节中第一个占用之后剩余的空间)是否可以存放第二个,是就存放,否则重新开辟四字节的空间来存放第二个数据,以此类推,直至所有成员存放结束。使用位字段表述数据时,如果超过了某个字段所能表述数的范围的话,结果不可预料的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值