C语言结构体

一、什么是结构体?

我们知道C语言有内置类型,比如char、short、int、long、float、double等,但在生活中我们如果去描述一个人,一本书该怎么描述呢?人有许多属性比如身高,体重,年龄等单一的内置类型是不能完全表示出来的,C语言为了解决这种问题就增加了结构体这种自定义的数据类型,让程序员可以创造合适的类型去表述它们。

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

这就是结构体的表示形式,结构体的关键字是struct,结构体是一些值的集合,这些值称为成员变量,结构体的每个成员的类型可以是任意的,如指针、数组、内置类型,甚至是结构体类型。

如描述一本书,代码可以写成如下形式:

struct Book
{
    char name[20];//书名
    float price;//价格
    char author[20];//作者
};

二、结构体变量的定义和初始化

通过上面的代码,我们已经知道了一个结构体的形式,接下来我们具体说一说结构体变量怎么定义。

struct Book
{
    char name[20];//书名
    float price;//价格
    char author[20];//作者
}s1;

struct Book s2;

上述代码在结构体后有一个是s1,s1是声明结构体的同时定义结构体变量,s2是类型名定义的结构体变量,两种方式都可以。

那么单单定义是不行的,我们要对结构体变量进行初始化。

struct Book s2 = {"C程序与设计",19.9,"xxx"}

这就是简单的初始化,按结构体成员变量顺序初始化,当然,我们也可以指定顺序,代码如下:

struct Book s2 = {.price = 19.9,.name = "C程序与设计",.author = "xxx"}

如果对s1初始化则可以直接在其后面初始化,代码如下:

struct Book
{
    char name[20];//书名
    float price;//价格
    char author[20];//作者
}s1={"C陷阱与缺陷",29.9,"xxxxx"};

如果结构体中包含结构体,像下面情况:

struct Student
{
    char name[20];
    struct Book b;
};

struct Student s={"zhangsan",{"C设计",39.9,"xx"}};

结构体变量就可以像这样初始化。

三、结构体成员如何访问?

通过上述,我们已经知道结构体变量的定义和初始化,那么我们如何去访问它们呢?结构体成员的直接访问是通过点操作符(.)访问的,有的地方叫句点操作符。点操作符接受两个操作数。

struct Point
{
    int x;
    int y;
};

int main()
{
    struct Point p={1,2};
    printf("%d %d\n",p.x,p.y);//打印结果为:1 2
    return 0;
}

代码中,p.x就是通过点操作符进行访问的,p和x是两个操作数。

那还有没有其他访问方式呢?答案是有的,下面请看代码:

struct Point
{
    int x;
    int y;
};

int main()
{
    struct Point p={1,2};
    struct Point* po=&p;
    printf("%d %d\n",po->x,po->y);//打印结果为:1 2
    return 0;
}

我们知道指针是非常"强大"的,当然也有结构体指针,C语言给出了箭头操作符(->),po是结构体指针通过箭头操作符可以访问到结构体的成员变量。

四、结构体内存对齐

在vs2019环境下,short类型变量占2个字节,int类型变量占4个字节,那么一个结构体变量在内存中会占多少个字节呢?这就涉及到结构体内存对齐,下面先介绍结构体内存对齐规则:1.结构体的第⼀个成员对齐到和结构体变量起始位置偏移量为0的地址处。2.其他成员变量要对齐到某个数(对齐数)的整数倍的地址处。

对齐数=编译器默认的⼀个对齐数与该成员变量大小的较小值。

在vs2019环境下,编译器的默认对齐数是8

在Linux和gcc中没有默认对齐数,对齐数就是成员自身大小

3.结构体总大小为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对齐数中最⼤的)的整数倍。4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对齐数的整数倍处,结构体的整体大小就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。
我们现在只需要记住怎么求对齐数即可,其他不用担心,接下来我会一一介绍。

请看下面代码:

struct S1
{
    char c1;//对齐数为1
    int a;//对齐数为4
    char c2;//对齐数为1
};
int main()
{
    printf("%zd",sizeof(struct S1));
    return 0;
}

我们根据代码来具体分析,c1的大小为1字节,在vs2019下默认对齐数为8,1小于8,所以c1的对齐数为1,依次类推a的对齐数为4,c2的对齐数为1,我们第一步工作已经完成了。

在vs2019环境下,根据规则1、2我们知道c1处的偏移量为0,存放完c1后偏移量加1,此时偏移量为1,接着到变量a了,变量a的对齐数为4,偏移量为1不是4的倍数,偏移量为4可以满足,因此变量a要在偏移量为4的位置开始存放4字节,存放完后,偏移量为8,最后存放变量c2,c2的对齐数为1,8是1的倍数所以紧接着存放c2,然后偏移量加1,此时偏移量为9,至此结构体中3个成员变量已经存放完毕,我们再看规则3,变量c1,a,c2中最大对齐数为4,9不是4的倍数,所以偏移量要到12,最后结构体大小就是从偏移量为0的位置于偏移量为12的位置之间的字节数,即12字节。

我们也可以利用#pragma这个预处理指令修改编译器的默认对齐数,例如:

#pragma pack(1)

//代码


#pragma pack()

第一个#pragma就可以将编译器的默认对齐数改为1,第二个#pragma就可以使对齐数回到原来的对齐数。

为什么会存在内存对齐呢?

⼤部分的参考资料都是这样说的:

1. 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2. 性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8的倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。

总体来说:结构体的内存对齐是拿空间来换取时间的做法。

以上就是全部内容了,祝大家天天开心!

  • 21
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
代码下载:完整代码,可直接运行 ;运行版本:2022a或2019b或2014a;若运行有问题,可私信博主; **仿真咨询 1 各类智能优化算法改进及应用** 生产调度、经济调度、装配线调度、充电优化、车间调度、发车优化、水库调度、三维装箱、物流选址、货位优化、公交排班优化、充电桩布局优化、车间布局优化、集装箱船配载优化、水泵组合优化、解医疗资源分配优化、设施布局优化、可视域基站和无人机选址优化 **2 机器学习和深度学习方面** 卷积神经网络(CNN)、LSTM、支持向量机(SVM)、最小二乘支持向量机(LSSVM)、极限学习机(ELM)、核极限学习机(KELM)、BP、RBF、宽度学习、DBN、RF、RBF、DELM、XGBOOST、TCN实现风电预测、光伏预测、电池寿命预测、辐射源识别、交通流预测、负荷预测、股价预测、PM2.5浓度预测、电池健康状态预测、水体光学参数反演、NLOS信号识别、地铁停车精准预测、变压器故障诊断 **3 图像处理方面** 图像识别、图像分割、图像检测、图像隐藏、图像配准、图像拼接、图像融合、图像增强、图像压缩感知 **4 路径规划方面** 旅行商问题(TSP)、车辆路径问题(VRP、MVRP、CVRP、VRPTW等)、无人机三维路径规划、无人机协同、无人机编队、机器人路径规划、栅格地图路径规划、多式联运运输问题、车辆协同无人机路径规划、天线线性阵列分布优化、车间布局优化 **5 无人机应用方面** 无人机路径规划、无人机控制、无人机编队、无人机协同、无人机任务分配 **6 无线传感器定位及布局方面** 传感器部署优化、通信协议优化、路由优化、目标定位优化、Dv-Hop定位优化、Leach协议优化、WSN覆盖优化、组播优化、RSSI定位优化 **7 信号处理方面** 信号识别、信号加密、信号去噪、信号增强、雷达信号处理、信号水印嵌入提取、肌电信号、脑电信号、信号配时优化 **8 电力系统方面** 微电网优化、无功优化、配电网重构、储能配置 **9 元胞自动机方面** 交通流 人群疏散 病毒扩散 晶体生长 **10 雷达方面** 卡尔曼滤波跟踪、航迹关联、航迹融合

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值