C语言——结构体(位段)、联合体、枚举

hello,大家好!我是柚子,今天给大家分享的内容是C语言中的自定义类型结构体、联合体以及枚举,有什么疑问或建议可以在评论区留言,会顺评论区回访哦~

一、结构体 struct

a.结构体声明

不同于数组的是,结构体中的每个成员可以是不同类型的变量;而数组是一组相同元素的集合。(一)结构的声明

例如:

//结构体声明
struct Str
{char name[20];char sex[20];int num;int age;
};//注意分号不能丢!!!

(二)结构体变量的创建和初始化

#include<stdio.h>
//结构体声明
struct Str
{char name[20];char sex[20];int num;int age;
};//注意分号不能丢!!!
int main()
{struct Str s = { "丁鸣","女",2024001,18 };	//注意成员的顺序,不要乱!printf("name:%s\n", s.name);printf("sex:%s\n", s.sex);printf("num:%d\n", s.num);printf("age:%d\n", s.age);return 0;
}

(三)结构体的特殊声明

 先看代码:

//匿名结构体
struct
{int a;int b;int c;
}s;
struct
{int a;int b;int c;
}a[100],*p;

 上述两种结构体在声明的时候省略了结构体标签,那如果将第一个结构体s的地址直接给p,能不能行的通呢??

//匿名结构体
struct
{int a;int b;int c;
}s;
struct
{int a;int b;int c;
}*p;
int mian()
{p = &s;//是否合法?return 0;
}

 如果你将代码放在VS上你就会发现它会直接报错;第一,编译器会把上边两个声明当成完全不同的两个类型,所以是非法的;第二,匿名结构体类型,如果没有对结构体类型重命名的话,基本上只能用一次。

(四)结构体的自引用

在结构体中包含一个类型为该结构体本身行不行???

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

如果可以的话,那么sizeof(struct Node)的大小为多少呢?所以,这么写是错误的。

为什么?

因为一个结构体中再包含一个同类型的结构体变量,这样的话结构体变量的大小就会无穷大,是不合理的。

正确的自引用方式如下:

//正确的自引用
struct Node
{int data;struct Node* next;//存放节点地址
};

 我们再来看一段代码:

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

这样的代码是否可行?

当然是大错特错啦,你这个Node命名还没完成,你就提前开始使用,肯定是错的。

正确的应该这么用:

//正确的typedef
typedef struct Node
{int data;struct Node* next;
}Node;

b.结构体内存对齐

(一)对齐原则:
1.结构体的第一个成员对齐到和结构体变量起始位置偏移量为0的地址处

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

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

-Vs中默认的值为8 
-Linux中gcc没有默认对齐数,对齐数就是成员自身的大小

3.结构体总大小为最大对齐数(结构体中每个成员变量都有一个对齐数,所有对齐数中最大的)整数倍

4.如果嵌套了结构体的情况,嵌套的结构体成员对齐到自己的成员中最大对齐数的整数倍结构体的整体大小就是所有最大对齐数(含嵌套结构体中成员的对齐数)的整数倍

(二)为什么存在内存对齐?

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

2.性能原因: 
数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问(为了访问效率更高)。

假设一个处理器总是从内存中取8个字节,则地址必须是8的倍数。如果我们能保证将所有的double类型的数据的地址都对齐成8倍数,那么就可以用一个内存操作来读或者写值了。否则,我们可能需要执行两次内存访问,因为对象可能被分放在两个8字节内存块中。

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

所以,为了让我们既满足对齐,又满足节省空间,我们要尽可能的让占用空间小的成员集中在一起         

(三) 修改默认对齐数

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

//#pragma
#pragma pack(1)	//设置默认对齐数1、4、8....
struct s
{char c1;int i;char c2;
};
#pragma pack()	//取消默认对齐数
int main()
{printf("%d\n", sizeof(s));return 0;
}

(四)结构体传参

//结构体传参
struct S
{int data[1000];int num;
};
//①
void print1(struct S t)
{printf("%d %d\n", t.data[3], t.num);
}
//②
void print2(const struct S* pt)
{printf("%d %d\n", pt->data[3], pt->num);
}
int main()
{struct S s = { {1,2,3,4,5,6},10};print1(s);print2(&s);return 0;
}

一般我们选择第二种方法print2传参,不管是在空间上还是在性能上都是比较好的选择!!但是为了安全起见还是会加上const。

原因:函数传参的时候,参数时需要压栈的,会有时间和空间上的系统开销。

           如果传递一个过大的结构体变量,参数压栈的系统开销较大导致性能下降。

结论:结构体传参的时候,要传结构体的地址。

(五)结构体实现位段

什么是位段?(位表示:二进制位)

位段是基于结构体的

位段的声明和结构是类似的,有两个不同
1.位段的成员必须是int、unsigned int 或signed int,在C99中位段成员的类型也可以选择其他类型。

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

//位段
struct A
{int a : 2;int b : 5;int c : 10;int d : 30;	//一共47个比特位,两个int型
};
int main()
{printf("%d\n", sizeof(A));	//8return 0;
}

位段的出现其实就是为了节省空间的。

位段的内存分配:

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

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

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

c.结构体变量的定义和初始化

二、结构成员访问操作符

结构体成员依据结构体变量类型的不同,一般有2种访问方式,一种为直接访问,一种为间接访问,相同的成员名称依靠不同的变量前缀区分。

a.结构体成员的直接访问

直接访问应用于普通的结构体变量,直接访问使用结构体变量名.成员名

b.结构体成员的间接访问

间接访问应用于指向结构体变量的指针,间接访问使用(*结构体指针名).成员名或者使用结构体指针名->成员名

三、联合体(共用体)union

a.联合体类型的声明

//联合体
union u
{char c;int u;
};
int main()
{union u uu;printf("%zd\n", sizeof(uu));printf("%zd\n", &uu);printf("%zd\n", &(uu.c));printf("%zd\n", &(uu.u));return 0;
}

联合体的成员共用一块空间 ,两个成员不同时使用。

b.联合体的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小。

c.联合体大小的计算

联合提的大小至少是最大成员的大小。(X)

当最大成员的大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐的整数倍。(

//计算
union U
{char c[5];	//5//按数组中的元素来算:1 8 1int a;	//4//4 8 4
};
int main()
{printf("%zd\n", sizeof(union U)); //8return 0;
}

联合体也是存在对齐的。 

d.相同成员的结构体和联合体的对比

e.联合体的应用:

使用联合体是可以节省空间的,比如,我们要搞一个活动,要上线一个礼品兑换单,礼品兑换单中有三种商品 : 图书、杯子、衬衫。

每一种商品都有:库存量、价格、商品类型和商品类型相关的其他信息。

图书:书名、作者、页数
杯子:设计
衬衫:设计、可选颜色、可选尺寸

struct gift_1ist
{//库存量、价格、商品类型int stock_num;double price;int item_type;union {//图书:书名、作者、页数struct{char title[20];char author[20];int num_pages;}book;//杯子:设计struct{char design[30];}mug;//衬衫:设计、可选颜色、可选尺寸struct{char design[30];int color;int sizes;}shirt;}item;
};

举例二: 

union U
{int n;//4struct S{char c1;char c2;char c3;char c4;}s;//4
};
int main()
{union U u = { 0 };u.n = 0x11223344;//拿出每个字节里的内容,巧妙利用联合体成员占用同一个空间printf("%x %x %x %x\n", u.s.c1, u.s.c2, u.s.c3, u.s.c4);return 0;
}

四、枚举 enum

a.枚举类型的声明

枚举就是可以一一例举,把可能的取值一一列举。

//枚举 enum
enum Sex
{//性别MALE,FEMALE,SECRET
};
int main()
{printf("%d\n", MALE);printf("%d\n", FEMALE);printf("%d\n", SECRET);return 0;
}

b.枚举类型的优点

我们可以使用#define定义常量,为什么非要使用枚举?
枚举的优点: 
1.增加代码的可读性和可维护性 

2.和#define定义的标识符比较枚举有类型检查,更加严谨。

3.便于调试,预处理阶段会删除#define定义的符号

4.使用方便,一次可以定义多个常量

5.枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用

今天的分享就先到这里,我们下期不见不散!!!拜拜~

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

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

相关文章

【CSP试题回顾】202212-2-训练计划

CSP-202212-2-训练计划 解题思路 输入和初始化&#xff1a; 首先&#xff0c;代码从输入中获取项目的截止日期和项目数量。然后&#xff0c;它初始化一个项目列表&#xff0c;每个项目都有其依赖项、被依赖的项目集合、完成时间、总完成时间&#xff08;包括依赖链&#xff09…

【JavaSE】面向对象——多态性

多态性 多态性的概念 所谓多态性&#xff0c;理解为一个事物的多种形态。具体点就是去完成某个动作时&#xff0c;不同的对象会产生不同的状态。 多态性的好处 多态在Java中指的是父类的引用指向子类的对象&#xff0c;或者可以说是子类的对象赋给父类的引用。这样在我们的…

SpringBoot实现分页模糊查询

1. Navicat查询数据 Navicat中查询所有数据 SELECT * FROM sys_user;Navicat中查询前两条数据&#xff08;俩种方式&#xff09; SELECT * FROM sys_user LIMIT 2; //从0开始&#xff0c;第一个参数是起始位置即(pageNum-1)*pageSize&#xff0c;第二个参数是步长 SELECT * …

项目部署后 通过公网IP访问不到的问题解决

目录 1.检查项目是否在运行(第二行命令) 2.检查所用服务器防火墙是否打开 3.检查linux系统防火墙有没有打开 问题如图: 首先确保项目已经成功部署 1.检查项目是否在运行(第二行命令) 第一行命令是监听58080端口,我的项目是使用该端口 2.检查所用云服务器防火墙是否打开 我…

分享77个Html杂七杂八模板,总有一款适合您

分享77个Html杂七杂八模板&#xff0c;总有一款适合您 77个Html杂七杂八模板下载链接&#xff1a;https://pan.baidu.com/s/1-RyIKaxdCu3dbnlMFMwviw?pwd8888 提取码&#xff1a;8888 学习知识费力气&#xff0c;收集整理更不易。知识付费甚欢喜&#xff0c;为咱码农谋福…

每日好题3.5

前缀和 这个题目巨妙&#xff0c;打的时候没写出来&#xff0c;后面补题发现太牛了 思路&#xff1a;当前区间左端点 L L L &#xff0c;当我们向右移动一次&#xff0c;就相当于&#xff0c;原式 - f ( L ) f ( L 1 e 18 ) f(L) f(L 1e18) f(L)f(L1e18)&#xff0c;值就…

linuxOPS基础_服务器构成

服务器的重要结构组成 家用电脑组成&#xff1a; CPU、主板、内存条、显卡、硬盘、电源、风扇、网卡、显示器、机箱、键盘鼠标等等。 CPU CPU是电脑的大脑&#xff0c; CPU发展史&#xff1a; 32 位CPU&#xff1a;最大的内存寻址地址2^32&#xff0c;大约4G的大小。 CP…

CSS3新特性

简介 继CSS2之后&#xff0c;CSS3增加了很多新的特性&#xff0c;虽然W3C仍在规范中&#xff0c;但是很多新的CSS3属性已经在很多现代浏览器中得到了支持。 CSS3边框 在CSS3中&#xff0c;可以创建圆角边框&#xff0c;添加边框阴影&#xff0c;设置边框图片&#xff0c;利用…

计算机组成原理之机器:计算机系统的基本概念

计算机组成原理之机器 笔记来源&#xff1a;哈尔滨工业大学计算机组成原理&#xff08;哈工大刘宏伟&#xff09; Chapter1&#xff1a;计算机系统的基本概念 1.1 计算机系统简介 从物理构成的角度对计算机系统分层 计算机组成原理主要关注微体系结构&#xff08;Mirco-arc…

【无标题】计算机主要应用于哪些领域

科学计算&#xff08;或称为数值计算&#xff09;、数据处理&#xff08;信息管理&#xff09;、辅助工程、生产自动化、人工智能。1、科学计算&#xff08;或称为数值计算&#xff09;&#xff1a;早期的计算机主要用于科学计算。目前&#xff0c;科学计算仍然是计算机应用的一…

【原理图PCB专题】Allegro模块化移动器件报...has the LOCKED property怎么解锁?

在模块化原理图时,PCB也需要做一个模块.mdd文件。这时需要先画好图纸然后再制作模块化文件。 修改文件时会发现模块化器件报错,无法编辑模块内部器件和走线,器件和走线都被LOCKED,如下所示报错内容: Symbol "U1" Selected Cannot edit Symbol "U1". M…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:组件标识)

id为组件的唯一标识&#xff0c;在整个应用内唯一。本模块提供组件标识相关接口&#xff0c;可以获取指定id组件的属性&#xff0c;也提供向指定id组件发送事件的功能。 说明&#xff1a; 从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容…

代码随想录算法训练营第九天

28. 实现 strStr() &#xff08;本题可以跳过&#xff09; 方法&#xff1a; 方法一&#xff1a; 暴力法 i 表示最多能移动到n-m位置&#xff0c; 超过则退出循环。j表示haystack 初始位置k表示needle的初始位置如果haystack [j] needle[k]且 k<m 则 j, k; 如果 km 则返…

OJ输入问题+准备

写在之前&#xff1a; 发现题目输入是这样的&#xff1a; 我的问题&#xff1a;如何通过空格分割这些输入的字符串并分别保存&#xff01;&#xff01;&#xff08;C语言scanf好解决一点但我选择C....&#xff09; C引入了ostringstream、istringstream、stringstream这三个类…

DevOps中集成自动化测试的具体案例

在DevOps中集成自动化测试的具体案例可以从多个角度进行分析,包括金融行业、分布式系统、大型企业等不同领域的实践。以下是几个具体的案例: 金融行业的DevOps实践:在金融行业中,DevOps被广泛应用于提升软件开发和运营的效率。例如,通过解析后台接口代码日志格式,自动化生…

linuxOPS基础_运维概述,及其泛概念

运维岗位定义 什么是运维&#xff1f; ​ 在技术人员&#xff08;写代码的&#xff09;之间&#xff0c;一致对运维有一个开玩笑的认知&#xff1a;运维就是修电脑的、装网线的、背锅的岗位。 ​ IT运维管理是指为了保障企业IT系统及网络的可用性、安全性、稳定性&#xff0…

SPI总线知识总结

1 SPI的时钟极性CPOL和时钟相位CPHA的设置 1.1 SPI数据传输位数 SPI传输数据过程中总是先发送或接收高字节数据&#xff0c;每个时钟周期接收器或发送器左移一位数据。对于小于16位的数据&#xff0c;在发送前必须左对齐&#xff0c;如果接收的数据小于16位&#xff0c;则采用软…

汽车碰撞与刮伤的实用维修技术,汽车的车身修复与涂装修补教学

一、教程描述 本套汽车维修技术教程&#xff0c;大小7.44G&#xff0c;共有60个文件。 二、教程目录 01-汽车车身修复教程01-安全规则&#xff08;共3课时&#xff09; 02-汽车车身修复教程02-汽车结构&#xff08;共3课时&#xff09; 03-汽车车身修复教程03-汽车修复所使…

为什么Spring Cloud 应用程序中,应用程序的加载配置必须写在bootstrap.yaml这个配置文件中,是在哪里规定的?

在 Spring Cloud 应用程序中&#xff0c;bootstrap.yaml&#xff08;或bootstrap.properties&#xff09;的使用并非强制性的&#xff0c;但它扮演着一个特定的角色&#xff0c;主要是因为 Spring Cloud 的设计和工作流程。 背景和设计 Spring Cloud 构建在 Spring Boot 之上…

鸿蒙 Stage模型-应用组件-配置、UIAbility

前提&#xff1a;基于官网3.1/4.0文档。参考官网文档 基于Android开发体系来进行比较和思考。&#xff08;或有偏颇&#xff0c;自行斟酌&#xff09; 一、概念 可以看到分为运行期、编译器&#xff0c;主要关注UIAbility&#xff08;类似Activity&#xff0c;UI相关&#xff0…