【C语言进阶】C语言进阶教程:利用结构体、联合体和枚举自定义数据类型

news2024/9/20 12:39:26

📝个人主页🌹:Eternity._
⏩收录专栏⏪:C语言 “ 登神长阶 ”
🤡往期回顾🤡:C语言内存管理函数
🌹🌹期待您的关注 🌹🌹

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

❀C语言自定义类型

  • 📒1. 结构体
    • 🌞结构体的声明
    • 🌙结构体变量的定义
    • ⭐结构体内存对齐
    • 🌄结构体传参
  • 📚2. 位段
    • 🍁位段的应用
  • 📜3. 枚举
  • 📝4. 联合体
  • 📖5. 总结


前言:在C语言的浩瀚宇宙中,自定义类型如同璀璨星辰,为开发者们提供了无限的可能性和创造力。作为一门历史悠久且功能强大的编程语言,C语言不仅以其接近硬件的特性和高效的执行效率著称,更以其灵活的数据结构定义方式赢得了广泛的赞誉。而自定义类型,正是这一灵活性的集中体现

当我们深入C语言的编程世界时,会发现仅仅依靠基本数据类型(如int、float、char等)往往难以满足复杂问题的需求。这时,自定义类型便成为了我们手中的利器。通过结构体(struct)、联合体(union)、枚举(enum)等高级特性,我们可以根据实际需求,设计出既符合逻辑又便于管理的数据结构。这些自定义类型不仅能够帮助我们更好地组织代码,提高代码的可读性和可维护性,还能在性能优化、内存管理等方面发挥重要作用

本文旨在通过深入浅出的方式,带领读者走进C语言自定义类型的世界。我们将从基础概念讲起,逐步深入到结构体、联合体、枚举等自定义类型的定义、使用及优化技巧。通过丰富的实例和详细的解析,帮助读者掌握自定义类型的设计方法和实现技巧,从而在C语言编程的道路上迈出坚实的一步

让我们一起,在C语言的海洋中扬帆起航,探索未知,创造未来!


📒1. 结构体

C语言中的结构体(Struct)是一种用户自定义的数据类型,它允许你将不同类型的数据项组合成一个单一的类型。结构体在C语言中非常有用,特别是在处理复杂的数据时,比如表示一个学生的信息(包括姓名、年龄、学号等)或者一个产品的详细信息(包括名称、价格、库存量等)


🌞结构体的声明

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

学生的信息结构体代码示例 (C语言):


struct Student
{
	char name[20];//名字
	int age;//年龄
	char id[20];//学号
};

特殊的声明

匿名结构体类型代码示例 (C语言):

struct // 省略掉了结构体标签
{
	int a;
	char b;
	float c;
}x;

struct // 省略掉了结构体标签
{
	int a;
	char b;
	float c;
}a[20], *p;

注意:编译器会把上面的两个声明当成完全不同的两个类型


结构的自引用

在结构中包含一个类型为该结构本身的成员是被允许的

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

但是我们通常会用typedef来重命名,虽然将结构体重命名了,在结构体内部定义时还是要用原来的名称

typedef struct Node
{
	int data;
	struct Node* next; // 此处是struct Node* 而不是 Node*
}Node;

🌙结构体变量的定义

struct Point
{
	int x;
	int y;
}p1; //声明类型的同时定义变量p1
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = { 1, 2 };

struct Stu //类型声明
{
	char name[15];//名字
	int age; //年龄
};
struct Stu s = { "pxt", 20 };//初始化

struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

⭐结构体内存对齐

来计算一下结构体的大小

在这里插入图片描述

来计算一下结构体的大小如果不了解的话可能会觉得是
6 6 13

在这里插入图片描述

为什么最终结果会是这样呢?
这就要掌握首先得掌握结构体的对其原则


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

为什么存在内存对齐?
大部分的参考资料都是如是说的:

  1. 平台原因(移植原因):
    不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  2. 性能原因:
    数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
    原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

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


修改默认对齐数

#pragma :修改默认对齐数

#pragma pack(8)//设置默认对齐数为8
struct S1
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

#pragma pack(1)//设置默认对齐数为1
struct S2
{
	char c1;
	int i;
	char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认

int main()
{
	//输出的结果是什么?
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	return 0;
}

在这里插入图片描述


🌄结构体传参

结构体传参有两种,传值调用和传址调用

在这里插入图片描述
两种方法都是可行的,但是也有区别

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

如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。

因此结构体传参的时候,要传结构体的地址。


📚2. 位段

我们在之前初步了解结构体的时候简单介绍了一下位段,这里我们就不继续介绍了,不太清楚的可以回头了解一下


🍁位段的应用

在这里插入图片描述


📜3. 枚举

C语言中的枚举(Enumeration)是一种基本的数据类型,它允许程序员为整数指定一个更易读的名字。枚举类型本质上是一种特殊的整型,但它使得代码更加清晰易懂,因为它为整数值赋予了语义上的含义。枚举通过关键字enum来定义

枚举类型的定义:

enum Color//颜色
{
	RED, // 枚举常量
	GREEN,
	BLUE
};

enum Day//星期
{
	Mon,
	Tues,
	Wed,
	Thur,
	Fri,
	Sat,
	Sun
};

这些枚举常量都是有值的,默认从0开始,一次递增1,当然在定义的时候也可以赋初值

enum Color//颜色
{
	RED = 1,
	GREEN = 3,
	BLUE = 5
};

枚举的优点

  • 增加代码的可读性和可维护性
  • 和#define定义的标识符比较枚举有类型检查,更加严谨
  • 防止了命名污染(封装)
  • 便于调试
  • 使用方便,一次可以定义多个常量

枚举的使用

enum Color//颜色
{
	RED = 1,
	GREEN = 2,
	BLUE = 4
};
int main()
{
	enum Color clr = GREEN;//只能拿枚举常量给枚举变量赋值,才不会出现类型的差异。
	return 0;
}

📝4. 联合体

C语言中的联合体(Union)是一种特殊的数据类型,它允许在相同的内存位置存储不同的数据类型。联合体提供了一种方式来存储可能具有不同大小和数据类型但同时在任何时候只使用一个的数据。这意味着,联合体中的所有成员共享同一块内存区域,这块区域的大小足以存储联合体中最长的成员

//联合类型的声明
union Un
{
	char c;
	int i;
};

int main()
{
	//联合变量的定义
	union Un un;
	//计算连个变量的大小
	printf("%d\n", sizeof(un));
	return 0;
}

联合的特点

联合的成员是共用同一块内存空间的,这样一个联合变量的大小,至少是最大成员的大小(因为联合至少得有能力保存最大的那个成员)

union Un
{
	int i;
	char c;
};

int main()
{
	union Un un;
	// 下面输出的结果是一样的吗?
	printf("%d\n", &(un.i));
	printf("%d\n", &(un.c));
	//下面输出的结果是什么?
	un.i = 0x11223344;
	un.c = 0x55;
	printf("%x\n", un.i);
	return 0;
}

首先两个成员的地址输出来是一样的,其次un.c会和un.i共用一块空间,un.c覆盖了un.i的一部分
在这里插入图片描述


联合大小的计算

  • 联合的大小至少是最大成员的大小
  • 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
union Un1
{
	char c[5]; // 5 bytes
	int i;
};
union Un2
{
	short c[7]; // 7 * 2 = 14 bytes 
	int i;
};
int main()
{
	//下面输出的结果是什么?
	printf("%d\n", sizeof(union Un1)); // 8
	printf("%d\n", sizeof(union Un2)); // 16
	return 0;
}

📖5. 总结

随着我们对C语言自定义类型探索的深入,我们不难发现,这一特性不仅是C语言灵活性和强大功能的重要体现,更是编程艺术中不可或缺的一部分。通过自定义类型,我们能够构建出既符合实际需求又高效运行的数据结构,为复杂问题的解决提供了有力的支持

我希望每一位读者都能珍惜这次学习C语言自定义类型的机会,不仅要在技术上有所收获,更要在思维方式和解决问题的能力上有所提升。愿你们在未来的编程道路上,能够灵活运用自定义类型这一利器,创造出更加精彩和高效的程序作品

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

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

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

相关文章

编译 ffmpeg 以支持AVS格式视频解码与解码

前言 当前文章介绍如何在Linux下使用FFmpeg转码其他视频格式到AVS格式的指南,包括编译FFmpeg以支持XAVS编码和如何使用FFmpeg进行转码。 AVS (Audio Video Coding Standard) 格式是一种由中国主导制定的视频编码标准,全称为“中国数字音视频编解码技术…

将星 x17 安装ubuntu 20.04 双系统

准备工作,包含关闭快速启动,关闭Secret Boot 1.进入控制面板选择小图标,找到电源选项 2.点击更改当前不可用的设置,关闭快速启动 3.开机启动时快速按F2,进入BIOS 4.选择Setup Utiltity,选择Security&#…

鲁大师8月新机性能/流畅/AI/久用榜:新机节奏放缓,但不乏小惊喜

虽说8月紧邻开学季,但机圈发布新机的节奏相较7月,明显放缓不少,或许是华为和苹果将在9月10日这天再次正面硬刚,让其他厂商感觉“亚历山大”,不冒险当出头鸟;亦或是各手机厂商正为骁龙8 Gen4和天玑9400新旗舰…

C++入门9——list的使用

目录 1.什么是list? 2.list的构造 3.list迭代器的使用(list iterator) 4.list capacity 5.list modifiers 6.list的其他操作 1.什么是list? 在官网中,对list有这样的介绍: Lists are sequence co…

如何在VSCODE中查看西门子PLC的SCL程序?

如何在VSCODE中查看西门子PLC的SCL程序? 首先,下载并安装VSCODE, 安装完成后,默认为英文界面,点击左侧扩展栏,搜索中文语言包,并点击安装,安装完成后会提示重启,重启之后就会显示中文, 同样,在扩展中搜索SCL插件包,并点击安装, 安装完成之后,可以新建一个文本文件…

在 Elastic 8.15 中使用最少的代码快速构建 RAG

作者:来自 Elastic Han Xiang Choong Elastic 8.15 已经发布,语义搜索比以往任何时候都更容易实现。 我们将介绍如何在 15 分钟内完成所有这些任务: 将你的文档存储在某些数据存储服务中,例如 AWS S3 Bucket设置 Elastic Search…

java项目docker部署时进行热部署

本文需要pontwiner进行配合操作 1.上传文件到对应服务器,可以通过xftp等文件上传工具进行文件上传 2.获取docker imagId XX为项目部署名称 例如:test-server docker ps -a |grep XX 3.复制文件到docker容器的/tmp目录下 docker cp XXXX.class im…

做seo要注意的各种细节,你都注意到了吗

在实施seo时,关注各种细节是至关重要的。 这些细节始于网站的初始设计,包括选择合适的主机、规划网站结构、优化网站内容,以及建立内部和外部链接的策略等。此外,确保网站对搜索引擎友好,涵盖从URL的设计到内容的优化…

kafka的安装和启动

一、kafka介绍 1,kafka简单介绍 kafka是一款分布式、支持分区的、多副本,基于zookeeper协调的分布式消息系统。最大的特性就是可以实时处理大量数据来满足需求。 2,kafka使用场景 1,日志收集:可以用kafka收集各种服务…

使用 Docker 部署和运行 RabbitMQ

使用 Docker 部署和运行 RabbitMQ 在本篇博客中,我将介绍如何通过 Docker 来运行 RabbitMQ 并使用其管理界面。还会讨论我在操作过程中遇到的常见问题及其解决方案。RabbitMQ 是一个开源的消息代理,用于跨应用程序发送、接收消息。在容器化环境中运行 R…

使用sysbench 简单测试io

sysbench最新版本地址 GitHub - akopytov/sysbench: Scriptable database and system performance benchmark centos在线安装 curl -s https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh | sudo bash sudo yum -y install sysbench 查看sysben…

vue3+ts封装类似于微信消息的组件

组件代码如下&#xff1a; <!--聊天页面-播放语言组件--> <template><div:class"[voice-message, { sent: isSent, received: !isSent }]":style"{ backgroundColor: backgroundColor }"click"togglePlayback"><!-- isSen…

解析查看elf文件的构成

x86下用clang编译一段c代码&#xff0c;编译成elf文件&#xff0c;读elf文件&#xff0c;dump出里面的所有段&#xff0c;并打印出段中的数据和含义以及汇编的内容 编写C代码 首先&#xff0c;编写一个简单的C程序&#xff0c;例如命名为example.c&#xff1a; 使用Clang编…

【YOLOv5模型部署】——TensorRT推理引擎安装与使用基于Flask的项目部署

声明&#xff1a;笔记是做项目时根据B站博主视频学习时自己编写&#xff0c;请勿随意转载&#xff01; 温馨提示&#xff1a;对于我的电脑没有Nvidia的独显&#xff0c;只有Intel的集显&#xff0c;最后导出时无法识别Nvidia显卡设备&#xff01;&#xff01;就没成功&#xf…

Java小白一文讲清Java中集合相关的知识点(四)

LinkedList底层结构 LinkedList底层实现了双向链表和双向队列特点可以添加任意元素&#xff0c;包括null,元素可以重复线程不安全&#xff0c;没有实现同步 LinkedList底层操作机制 LinkedList底层维护了一个双向链表LinkedList中维护了两个属性first和last分别指向首结点和…

如何启动vue ui,快速创建vue项目

1.查看自己是否已经安装了vue3.0脚手架版本&#xff0c;打开cmd命令框输入vue -V(大写为查看&#xff0c;此处查看的是脚手架的版本)。如果没有提示版本&#xff0c;而是命令不存在...则要进行下面的1.1操作 1.1安装Vue CIL&#xff0c;如果已安装&#xff0c;此步忽略。安装完…

计算机毕业设计选题推荐-中华诗词文化交流平台-Java/Python项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

快速搭建和运行Spring Boot项目的简易指南

对于非Java开发的后端开发人员而言&#xff0c;即便未曾接触过Java&#xff0c;也可能听说过Spring Boot这一框架。若想要快速搭建并运行一个Spring Boot项目&#xff0c;可以遵循以下步骤&#xff1a; 环境准备 **安装Java JDK&#xff1a;**确保您的开发环境中安装了Java J…

Android Studio编译时各类型网络超时优化方案

我们国家有很多长城&#xff0c;我觉得最重要的除了大家耳熟能详的西起嘉峪关&#xff0c;东至山海关的万里长城&#xff0c;还有一个叫GFW的国家长城防火墙&#xff0c;这个防火墙起初仅是为了禁止用户访问政治敏感信息&#xff0c;后来逐渐强大。。。目前最新进展是我们已和世…

142.环形链表二-力扣

142. 环形链表 II - 力扣&#xff08;LeetCode&#xff09; struct ListNode *detectCycle(struct ListNode *head) {struct ListNode *fasthead;struct ListNode *slowhead;while(fast && fast->next){fast fast->next->next;slow slow->next;if(fasts…