【C语言】自定义类型:结构体、枚举、联合

news2024/11/16 11:36:19

目录

1.结构体

1.1结构体类型

1.2结构体的自引用

1.3结构体的初始化

1.4结构体内存对齐

//对齐

//offsetof  

//修改默认对齐数

1.5结构体传参

 2.位段

2.1位段的内存开辟

2.2位段的内存分配

3.枚举

4.联合(共用体) 

//判断大小端


1.结构体

1.1结构体类型

常见的结构体就不赘述了哈~直接见下图。

匿名结构体:顾名思义,就是没有名字的结构体,在后续进程中不能直接使用,所以要在定义时就创建全局变量。

 

1.2结构体的自引用

小Tips:链表:数据结构——>数据在内存中存储的结构

struct Node
{
	int date;
	struct Node* next;//一个节点中包含同类型的下一个节点的地址
};
int main()
{
	struct Node n1;
	struct Node n2;
	n1.next = &n2;//n1中的next存放n2的地址
	return 0;
}

//重命名
typedef struct Node
{
	int date;
	struct Node* next;//注意这里的struct不能去掉
}Node;

1.3结构体的初始化

struct P
{
	int x;
	int y;
};
struct S
{
	int num;
	char ch;
	struct P p;
	float d;
};
int main()
{
	struct P p = { 1,2 };
	struct S s1 = { 100,'w',{6,8},3.14 };//顺序赋值
	struct S s2 = { .d = 5.2f,.p.x = 2,.p.y = 3,.ch = 'a',.num = 10 };//乱序赋值
	printf("%d %c %d %d %f\n", s1.num, s1.ch, s1.p.x, s1.p.y, s1.d);
	printf("%d %c %d %d %f\n", s2.num, s2.ch, s2.p.x, s2.p.y, s2.d);
	return 0;
}

1.4结构体内存对齐

结构体对齐规则:(拿空间换时间)

1> 结构体的第一个成员对齐到结构体在内存中存放位置的0偏移处;

2> 从第二个成员开始,每个成员都要对齐到一个对齐数的整数倍处;

(对齐数:结构体成员自身大小和默认对齐数的较小值;默认对齐数:VS环境下(与32位或64位无关)为8,Linux gcc 环境下没有对齐数,对齐数就是结构体成员的自身大小);

修改默认对齐数:#program pack() 

3> 结构体的总大小,必须是所有成员(包含嵌套结构体成员)的对齐数中最大对齐数的整数倍

4> 如果结构体中嵌套了结构体成员,要将嵌套的结构体成员对齐到该结构体中本身成员中最大对齐数的整数倍处;

5> 节省空间:尽量让占用空间小的成员集中在一起

//对齐

struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	char c1;
	char c2;
	int i;
};
int main()
{
	printf("%d\n", sizeof(struct S1));//12
	printf("%d\n", sizeof(struct S2));//8
	return 0;
}

 

//offsetof  

如果还不信(bushi,可以用 offsetof 来检验:

格式:offsetof (type,member)

功能:计算结构体中某变量相对于首地址的偏移。

头文件:#include<stddef.h>

 

//修改默认对齐数

#pragma pack(1)//修改默认对齐数为1,相当于不对齐
struct S
{
	char c1;
	int num;
	char c2;
};
#pragma pack()//取消修改的对齐数,恢复为默认8
int main()
{
	printf("%d\n", sizeof(struct S));//6
	return 0;
}

1.5结构体传参

struct S
{
	int data[1000];
	int num;
};
struct S s = { {1,2,3,4}, 1000 };

//结构体传参
void print1(struct S s)
{
	printf("%d\n", s.num);
}

//结构体地址传参
void print2(struct S* ps)
{
	printf("%d\n", ps->num);
}

int main()
{
	print1(s); //传结构体
	print2(&s); //传地址
	return 0;
}

以上两种方法,首选print2函数,因为函数传参时,参数需要压栈,时间和空间均有开销。如果传递的结构体对象过大时,参数压栈的系统开销比较大,会导致性能下降。(详见:函数栈帧的创建和销毁)

 2.位段

位:二进制(比特)位

1.位段的成员必须是 int、unsigned int 、signed int 或 char (整形家族);
2.位段的成员名后边有一个冒号和一个数字

3.位段只能在结构体中使用

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

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

6.从低位向高位使用,一次开辟一个类型大小,当剩下比特位不够存放下一个成员时,丢弃剩余比特位再开辟新的内存。

功能:与结构体相同,不过更节省空间(不需对齐)。

2.1位段的内存开辟

struct A
{
	int _a : 2;
	int _b : 5;
	int _c : 10;
	int _d : 30;
};
int main()
{
	printf("%d\n", sizeof(struct A));//8
	return 0;
}

解释:先开辟一个int类型即32个比特位,_a使用2个比特位,剩30个比特位;_b使用5个,剩25个;_c使用10个,剩15个;_d需要30个,余下的比特位不足,舍弃;再开辟一个新的int类型即32个比特位,_d使用30个,剩2个;总共开辟64个比特位,即8个字节。 

2.2位段的内存分配

struct S
{
	char a : 3;
	char b : 4;
	char c : 5;
	char d : 4;
};
int main()
{
	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;
	printf("%d\n", sizeof((s)));//3
}

3.枚举

1> 不初始化默认为 0,1,2,…;也可以初始化(负值也可);若一开始初始化后面又不初始化,则后面按照顺序递增一

2> 与#define相比,枚举有类型检查,且也不参与运算;

3> 大小为一个整型大小,4个字节

enum Sex
{
	female=4,//是逗号不是封号
	male,
	secret=3//最后一个没有逗号也没有封号
};
enum Color
{
	red,
	green,
	blue
};
int main()
{
	enum Sex s = male;
	//male = 5;常量不能改
	printf("%d\n", female);//4
	printf("%d\n", male);//5
	printf("%d\n", secret);//3
	return 0;
}

4.联合(共用体) 

定义:一种特殊的自定义类型,包含一系列成员,特征是这些成员共用同一块空间,但是不能同时使用。

大小:1> 联合的大小至少是最大成员的大小
           2> 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍(同结构体)。

union UN
{
	char c;//两个成员共用同一块空间
	int i;//不能同时使用
};
int main()
{
	union UN un;
	printf("%d\n", sizeof(un));//4
	printf("%p\n", &un);//这三个地址相同
	printf("%p\n", &(un.c));//同上
    printf("%p\n", &(un.i));//同上
	return 0;
}

 

union UN1
{
	char arr[5];//5
	int i;//4
};
union UN2
{
	short str[7];//14
	int j;//4
};
int main()
{
	union UN1 un1;
	union UN2 un2;
	printf("%d\n", sizeof(un1));//8
	printf("%d\n", sizeof(un2));//16
	return 0;
}

//判断大小端

int check_sys()
{
	union UN
	{
		char c;
		int i;
	}un;
	un.i = 1;
	return un.c;
}
int main()
{
	int ret = check_sys();
	if (ret == 1)
		printf("小端\n");
	else
		printf("大端\n");
	return 0;
}

要开学考啦,加油加油,再创辉煌!!

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

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

相关文章

【GO】k8s 管理系统项目23[前端部分–工作负载-Pod]

k8s 管理系统项目[前端部分–工作负载-Deployment] 1. 代码部分 1.1 准备工作 由于Pod页面和Deployment内容差不多.那么就直接把Deployment的内容复制过来.再做修改. 替换Deployment为Pod替换Deploy为Pod替换deployment为pod替换deploy为pod禁用新增的按钮,删除新增方法,表…

django后端服务、logstash和flink接入VictoriaMetrics指标监控

0.简介 通过指标监控可以设置对应的告警&#xff0c;快速发现问题&#xff0c;并通过相应的指标定位问题。 背景&#xff1a;使用的 VictoriaMetrics(简称 VM) 作为监控的解决方案&#xff0c;需要将 django 服务、logstash 和 flink 引擎接入进来&#xff0c;VM 可以实时的获…

SpringBoot:SpringBoot配置文件.properties、.yml 和 .ymal(2)

SpringBoot配置文件1. 配置文件格式1.1 application.properties配置文件1.2 application.yml配置文件1.3 application.yaml配置文件1.4 三种配置文件优先级和区别2. yaml格式2.1 语法规则2.2 yaml书写2.2.1 字面量&#xff1a;单个的、不可拆分的值2.2.2 数组&#xff1a;一组按…

操作系统权限提升(十八)之Linux提权-内核提权

Linux 内核提权 Linux 内核提权原理 内核提权是利用Linux内核的漏洞进行提权的&#xff0c;内核漏洞进行提权一般包括三个环节&#xff1a; 1、对目标系统进行信息收集&#xff0c;获取到系统内核信息及版本信息&#xff1b; 2、根据内核版本获取其对应的漏洞以及EXP 3、使…

第七届蓝桥杯省赛 C++ A/B组 - 四平方和

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4da;专栏地址&#xff1a;蓝桥杯题解集合 &#x1f4dd;原题地址&#xff1a;四平方和 &#x1f4e3;专栏定位&#xff1a;为想参加蓝桥杯的小伙伴整理常考算法题解&#xff0c;祝大家…

Docker简介与用法

文章目录1、Docker简介1.1、Docker能解决什么问题1.2、什么是虚拟机技术1.2.1、虚拟机的缺点1.3、什么是容器1.3.1、容器与虚拟机比较1.4、分析 Docker 容器架构1.4.1、Docker客户端和服务器1.4.2、Docker 镜像(Image)1.4.3、Docker 容器(Container)1.4.4、Docker 仓库(reposit…

Windows程序员学习Linux环境内存管理

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下Windows程序员如何学习Linux环境内存管理。由于很多程序在Windows环境下开发好后&#xff0c;还要部署到Linux服务器上去&#xff0c;所以作为Windows程序员有必要学习Linux环境的内存…

【计算机三级网络技术】 第三篇 IP地址规划技术

IP地址规划技术 文章目录IP地址规划技术一、IP 地址规划以及划分地址新技术1.IP地址的标准分类&#xff08;第一阶段&#xff09;2.划分子网的三级地址结构(第二阶段)3.构成超网的无类域间路由技术(第三阶段)4.网络地址转换技术(第四阶段)二、IP 地址分类1.A类、B类与C类IP地址…

数据的表示和运算

文章目录数制与编码进制间的转换BCD码定点数与浮点数定点数是什么&#xff1f;浮点数是什么&#xff1f;定点数与浮点数的区别机器数和真值原码、反码、补码、移码基本定义整数的加减法刷题小结最后数制与编码 进制间的转换 二进制、八进制、十进制、十六进制之间的转换不用多…

前端杂学1

1.简单且必须掌握的 1.MVVM是什么 将MVC中的V变为了MVVM&#xff0c;实现了双向绑定。其中VM就是vue的作用&#xff0c;这样页面的动态化可以通过vue来操作&#xff0c;而不是页面直接与后端操作&#xff0c;实现了前后端的分离 2.为什么vue采用异步渲染 &#xff1f; 调…

Kubernetes之服务发现

本文使用wordpressmysql搭建个人博客来讲解服务发现相关知识。 环境准备 wordpress需要连接到mysql才能正常工作&#xff0c;所以需要为mysql的pod创建一个mysql的svc&#xff0c;只要不删除重建svc&#xff0c;其IP不会变。 此时wordpress的pod需要连接mysql的svc的时候&…

HyperGBM用4记组合拳提升AutoML模型泛化能力

本文作者&#xff1a;杨健&#xff0c;九章云极 DataCanvas 主任架构师 如何有效提高模型的泛化能力&#xff0c;始终是机器学习领域的重要课题。经过大量的实践证明比较有效的方式包括&#xff1a; 利用Early Stopping防止过拟合通过正则化降低模型的复杂度使用更多的训练数…

第四阶段01-酷鲨商城项目准备

1. 关于csmall-product项目 这是“酷鲨商城”大项目中的“商品管理”项目&#xff0c;是一个后台管理项目&#xff08;给管理员&#xff0c;或运营人员使用的项目&#xff0c;并不是普通用户使用的&#xff09;&#xff0c;并且&#xff0c;只会涉及与发布商品可能相关的功能开…

企业工程项目管理系统平台(三控:进度组织、质量安全、预算资金成本、二平台:招采、设计管理)

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…

React(二):jsx事件绑定、条件渲染、列表渲染、jsx的本质、购物车案例

React&#xff08;二&#xff09;一、jsx事件绑定1.this的绑定方式2.jsx中绑定this的三种方式3.事件对象和传参&#xff08;1&#xff09;事件对象怎么传&#xff08;2&#xff09;其他参数怎么传&#xff1f;二、条件渲染1.直接if-else2.三元表达式3.利用逻辑中断4.案例练习5.…

HTML#5表单标签

一. 表单标签介绍表单: 在网页中主要负责数据采集功能,使用<form>标签定义表单表单项: 不同类型的input元素, 下拉列表, 文本域<form> 定义表单<input> 定义表单项,通过typr属性控制输入形式<label> 为表单项定义标注<select> 定义下拉列表<o…

【GO】31.grpc 客户端负载均衡源码分析

这篇文章是记录自己查看客户端grpc负载均衡源码的过程&#xff0c;并没有太详细的讲解&#xff0c;参考价值不大&#xff0c;可以直接跳过&#xff0c;主要给自己看的。一.主要接口&#xff1a;Balancer Resolver1.Balancer定义Resolver定义具体位置为1.grpc源码对解析器(resol…

异步通知实验

目录 一、异步通知简介 阻塞、非阻塞、异步通知区别 信号与信号修改测试 测试 二、驱动编写 1、定义fasync_struct 结构体指针变量 2、操作集添加fasync 3、实现imx6uirq_fasync 函数 4、关闭驱动文件操作 ​编辑 5、定时器处理函数 三、编写APP 1、编写信号的处理…

ElasticSearch 学习笔记总结(二)

文章目录一、ES JavaAPI 环境准备二、ES JavaAPI 索引1. 索引 创建2. 索引 查找3. 索引 删除三、ES JavaAPI 文档1. 文档 创建2. 文档 修改3. 文档 查询4. 文档 删除4. 文档 批量新增 和 批量删除5. 高级查询 索引全量查询6. 高级查询四、ES 集群1. ES集群 概念2. window 集群搭…

阿里P8:做测试10年我的一些经验分享,希望你们少走弯路

我是在2015年毕业的&#xff0c;当时是读的普通本科&#xff0c;不上不下的专业水平&#xff0c;毕业的时候&#xff0c;恰好遇到了金融危机。校园招聘里阴差阳错的巧合&#xff0c;让我走上了软件测试工程师的道路。 入职第一天&#xff0c;来了个高大上的讲师&#xff0c;记…