【零基础C语言】自定义类型:结构体

1.结构体的声明

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

我们描述一本书或者一个学生的时候可以这样写

//书 - 书名,作者,价格,序号struct book
{char _book_name[20];char _author[20];int price;char id[20];
};//学生 - 姓名,性别,年龄,学号
struct Stu
{char _name[20];char sex[10];int age;char id[20];
};

 2.结构体变量的创建和初始化

 

struct Stu
{char name[20];//名字int age;//年龄char sex[5];//性别char id[20];//学号
};int main()
{// 第一种初始化方式:需要按结构体成员顺序初始化struct Stu s1 = { "欧阳",20,"男","20240319" };// 第二种初始化方式:可以自定义顺序struct Stu s2 = { .age = 21,.sex = "女",.name = "阳区欠",.id = "20240318" };//输出S1printf("name: %s\n", s1.name);printf("age : %d\n", s1.age);printf("sex : %s\n", s1.sex);printf("id : %s\n", s1.id);printf("\n");//输出S2printf("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;
}

3.结构体的特殊声明 

 3.1匿名结构体类型

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

 前面两个结构体都省略了结构体的tag(标签)

 p = &x; 这行代码合理吗?

警告:
编译器会把上⾯的两个声明当成完全不同的两个类型,所以是⾮法的。
匿名的结构体类型,如果没有对结构体类型重命名的话,基本上只能使⽤⼀次。

 3.2结构体的自引用

struct Stu
{int data;struct Stu* next;
};

3.3重命名匿名结构体 - typedef

typedef struct
{int data;Stu* nxet;
}Stu;

 这样的重命名也会带来问题,就如上面的代码一样是不合法的,因为程序是由上向下运行的,所以在创建Stu* next 时Stu还未创建

 解决方案:定义的结构体不使用匿名结构体

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

 

4.结构体对齐 - 计算结构体大小

4.1对齐规则

  1.  结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处
  2.  其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处。对⻬数 = 编译器默认的⼀个对⻬数与该成员变量⼤⼩的较⼩值。-VS 中默认的值为 8 -Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩
  3. 结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构
  5. 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

下面以练习题来了解这四条规则吧
 

//练习1
int main()
{struct S1{			// 变量本身   vs   对齐数char c1;//    1       8     1int i;  //    4       8     4char c2;//    1       8     1};printf("%zd\n", sizeof(struct S1));
}// 根据规则二我们可以算出每个类型的对齐数// 根据规则一我们开始画图,从0开始,c1为char类型对齐数为1,所以第一格就可以给他,
// 第二个成员类型为int,对齐数为4,根据规则二前面也需要保障为4的整数倍处,所以在4填涂,然后留出4个格子
// 第三个成员类型为char,对齐数为1,在后面一格填图即可,最后整个结构体的大小要为最多对齐数的整数倍,所以填补到12格

 

// 以下练习大家可以自己画图计算试试//练习2
int main()
{struct S2{char c1;  // 1 8 1char c2;  // 1 8 1int i;    // 4 8 4};printf("%zd\n", sizeof(struct S2));//8//练习3struct S3{double d; //8 8 8char c;   //1 8 1int i;    //4 8 4};printf("%zd\n", sizeof(struct S3));//16//练习4-结构体嵌套问题struct S4{char c1;  // 1 8 1struct S3 s3;// 8 8 8double d; // 8 8 8};printf("%zd\n", sizeof(struct S4)); //32return 0;
}

画图参考:

 

 

 

 

 4.2为什么存在内存对齐

  1.  平台移植原因 :不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2.  性能原因:数据结构(尤其是栈)应该尽可能地在⾃然边界上对⻬。原因在于,为了访问未对⻬的内存,处理器需要作两次内存访问;⽽对⻬的内存访问仅需要⼀次访问。假设⼀个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对⻬成8的倍数,那么就可以⽤⼀个内存操作来读或者写值了。否则,我们可能需要执⾏两次内存访问,因为对象可能被分放在两个8字节内存块中。

总结:用空间换时间

 设计结构体时,又想满足对齐规则,又想节省空间,需要尽量将占用空间小的成员集中到一起

如:

int main()
{struct S1{char c1;int i;char c2;};struct S2{char c1;char c2;int i;};printf("%zd\n", sizeof(struct S1));printf("%zd\n", sizeof(struct S2));return 0;
}// S1的大小占比为12,而S2的大小占比为8。

4.3 修改默认对齐

 使用#pragma 预处理命令,可以改变编译的默认对齐数

 

#pragma pack(1)
struct S
{char c1;int i;char c2;
};
#pragma pack()int main()
{printf("%zd\n", sizeof(struct S)); // 6return 0;
}

 5.结构体传参

 

struct book
{char _book_name[20];int price;
};
struct book s1 = { "狂人日记",18 };
//结构体传参
void print1(struct book s1)
{printf("%s\n", s1._book_name);
}//结构体地址传参
void print2(const struct book* ps)
{printf("%s\n", ps->_book_name);
}
int main()
{print1(s1);print2(&s1);return 0;
}

上⾯的 print1 和 print2 函数哪个好些?
答案是:⾸选print2函数。

 print1 是传值调用,形参,是实参的一份拷贝,这意味着重新开辟一个空间复制一遍实参进行使用,这大大浪费了空间
 print2 是传址调用,使用的数据空间还是原来的,只要根据地址找寻即可,但是为了防止在访问时更改我们需要加上const


 6.结构体实现位段
 

 6.1什么是位段

  • 位段成员必须是整型,int/ unsigned int/ signed int,在C99中其他类型的位段成员也可以
  • 位段成员名后面有一个冒号和一个数字

 

struct S
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};// S是一个位段类型,那么位段S所占内存大小位多少?
int main()
{printf("%zd\n", sizeof(struct S)); // 8return 0;
}

 6.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 };
int main()
{s.a = 10;s.b = 12;s.c = 3;s.d = 4;printf("%zd\n", sizeof(struct S)); //3return 0;
}//空间是如何开辟的?// a:10 -> 01010   存储: 3 -> 010
// b:12 -> 01100   存储: 4 -> 1100
// c:3  -> 00011   存储: 5 -> 00011
// d:4  -> 00100   存储: 4 -> 0100
// 十进制   二进制// 图片没有存储的地方补0
//        最后就是 01100010 00000011 00000100
// 转换成16进制即可 0x62      0x03      0x04

 6.3段位跨平台问题

 

  1. int位段被当成有符号数还是⽆符号数是不确定的。
  2. 位段中最⼤位的数⽬不能确定。(16位机器最⼤16,32位机器最⼤32,写成27,在16位机器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当⼀个结构包含两个位段,第⼆个位段成员⽐较⼤,⽆法容纳于第⼀个位段剩余的位时,是舍弃剩余的位还是利⽤,这是不确定的。

总结:
跟结构相⽐,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。


6.4段位的使用注意事项

//段位是几个成员共用一个字节,所以无法通过scanf取地址输入struct S
{int _a : 2;int _b : 5;int _c : 10;int _d : 30;
};int main()
{struct S s = { 0 };//scanf("%d", &s._a); //err//正确的方式int b = 0;scanf("%d", &b);s._a = b;return 0;
}

 

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

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

相关文章

从头手搓一台ros2复合机器人(带机械臂)

一.前言 大家好呀,从本小节开始我们就步入了仿真篇,主要对机器人仿真进行介绍与操作,当然仿真有优点也有缺陷,基于对此学习,我们可以对上几小节创建的小车模型模拟硬件的特性, 比如: 有多重…

web学习笔记(三十三)

目录 1.严格模式 1.1严格模式的概念: 1.2严格模式在语义上更改的地方: 1.3如何开启严格模式 1.4严格模式应用上的变化 2.原型链 1.严格模式 1.1严格模式的概念: 严格模式有点像es5向es6过渡而产生的一种模式,因为es6的语法…

Python-GEE绘制DEM精美图片

目录 上传矢量和DEM获取添加颜色条参考文章 先连接上GEE的自己的项目 import ee import geemap geemap.set_proxy(port33210) ee.Authenticate() ee.Initialize(projecta-flyllf0313)上传矢量和DEM获取 使用Google Earth Engine(GEE)和Google Earth Eng…

linux:线程互斥

个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》 文章目录 前言一、线程互斥问题解释互斥量的接口 二、加锁的原理三、 死锁死锁四个必要条件避免死锁 总结 前言 本文是对于线程互斥的知识总结 一、线程互斥 问题 我们先看下面…

基础乱炖来吧

1,SSH框架和SSM区别 SSH:structspringhibernate,SSM:MVCspringmybatis struct入口是filter级别,对action类进行请求,一个action类对应一个请求、类拦截;spring-mvcservlet级别,方法级别请求&…

海外代理IP在跨境电商中的五大应用场景

在我国跨境电商的发展中,海外代理IP的应用日益广泛,它不仅帮助商家成功打入国际市场,还为他们在多变的全球电商竞争中保持优势。下面是海外代理IP在跨境电商中五个关键的应用场景。 1、精准的市场分析 了解目标市场的消费者行为、产品趋势以…

Java语言: JVM

1.1 内存管理 1.1.1 JVM内存区域 编号 名字 功能 备注 1 堆 主要用于存放新创建的对象 (所有对象都在这里分配内存) jdk1.8之后永久代被替换成为了元空间(Metaspace) 2 方法区(加、常、静、即) 被虚拟机加载的类信息(版本、字段、方法、接口…

汽车电子零部件(8):T_Box

前言: 网联汽车(Connected Vehicles ,CV)是一个广泛的概念,四个主要的CV线程已发展起来:互联、自主、共享和电动。这些应用于包括CV在内的垂直领域:汽车、通信、互联网和共享手机服务。中国汽车工程师学会(SAEC)提倡将车载ADAS(高级驾驶员辅助系统)与通信技术相结合…

(挖矿病毒清除)kdevtmpfsi 处理

Linux Centos 7 环境下的一台服务器CPU直接被打满,上服务器 top 命令看到了一个未知的 kdevtmpfsi 疯狂占用中,情况如下图: 同时阿里云检测平台,也同步提示对应容器出现的问题 问题原因: postgres RCE导致h2Miner蠕虫…

ASP.NET Core 8.0 WebApi 从零开始学习JWT登录认证

文章目录 前言相关链接Nuget选择知识补充JWT不是加密算法可逆加密和不可逆加密 普通Jwt(不推荐)项目环境Nuget 最小JWT测试在WebApi中简单使用简单使用运行结果 WebApi 授权,博客太老了,尝试失败 WebApi .net core 8.0 最新版Jwt …

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:ListItemGroup)

该组件用来展示列表item分组,宽度默认充满List组件,必须配合List组件来使用。 说明: 该组件从API Version 9开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。该组件的父组件只能是List。 使用说明 当List…

51单片机LED8*8点阵显示坤坤跳舞打篮球画面

我们作为一名合格的 ikun,专业的小黑子,这个重要的知识必须学会。 先看效果: 51LED点阵_鸡你太美 这里我们首先要用到延时函数Delay: void Delay(unsigned int xms) {unsigned char i, j;while(xms--){ i 2;j 239;do{while (-…

【PyQt】17-日历控件

文章目录 前言一、代码二、运行结果总结 前言 固定格式的表述 日期的获取 一、代码 #Author :susocool #Creattime:2024/3/19 #FileName:40-日历控件 #Description: 日历控件的展示 import sys from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQ…

V-JEPA模型,非LLM另外的选择,AGI的未来:迈向Yann LeCun先进机器智能(AMI)愿景的下一步

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

Redisson 分布式锁原理分析

Redisson 分布式锁原理分析 示例程序 示例程序: public class RedissonTest {public static void main(String[] args) {Config config new Config();config.useSingleServer().setPassword("123456").setAddress("redis://127.0.0.1:6379"…

最新Java面试题2【2024初级】

下载链接:博主已将以上这些面试题整理成了一个面试手册,是PDF版的 互联网大厂面试题 1:阿里巴巴Java面试题 2:阿里云Java面试题-实习生岗 3:腾讯Java面试题-高级 4:字节跳动Java面试题 5:字…

Apache Dolphinscheduler - 无需重启 Master-Server 停止疯狂刷日志解决方案

记录的是一个 3.0 比较难搞的问题,相信不少使用过 3.0 的用户都遇到过 Master 服务中存在一些工作流或者任务流一直不停的死循环的问题,导致疯狂刷日志。不过本人到现在也没找到最关键的触发原因,只是看到一些连锁反应带来的结果…… 影响因素…

第十届教育技术前沿国际会议(ICFET 2024)即将召开!

ICFET 2024 | Malacca, MalaysiaInstallation Documentation for your Bootstrap Templatehttp://www.ICFET.org/ 组织单位: 会议主题: 整合教育技术 社交媒体和社交网络 语义网 3.0 播客播放视频讲座 播客向学生提供反馈 Wiki 和博客在高等教育中的…

MySQL最实用面试题(2024-3-14持续更新中)

MySQL篇面试题 一、介绍 ​ 这是由小龙同学自己总结领悟的mysql面试题的解析,也是面试宝典 二、题目 1.数据库三大范式: –作用: ​ 使表结构清晰,减少数据冗余(简单讲就是重复),提高查询…

《探索AI辅助研发的未来之路》

在当今科技飞速发展的时代,人工智能(AI)已经逐渐渗透到各个领域,其中之一便是研发领域。AI辅助研发正以惊人的速度改变着我们对于创新和发现的理解。本文将从技术进展、行业应用、挑战与机遇、未来趋势、法规影响以及人才培养等方…