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

news/2024/9/13 9:08:59/文章来源:https://blog.csdn.net/EterNity_TiMe_/article/details/141885989

📝个人主页🌹: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 bytesint i;
};
union Un2
{short c[7]; // 7 * 2 = 14 bytes int i;
};
int main()
{//下面输出的结果是什么?printf("%d\n", sizeof(union Un1)); // 8printf("%d\n", sizeof(union Un2)); // 16return 0;
}

📖5. 总结

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

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

在这里插入图片描述

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

在这里插入图片描述

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

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

相关文章

运维领域的先进思想和趋势

在运维领域,除了“基础设施即代码(IaC)”之外,还有许多先进的思想和方法正在推动运维的进步。以下是一些关键的理念和趋势: 智能运维(AIOps):利用人工智能和机器学习技术来自动化和优…

如何实现网页多标签tab通讯?

通过websocket 无跨域限制需要服务端支持,成本高通过localStorage同域通讯(推荐) 同域的A和B两个页面A页面设置localStorageB页面可监听到localStorage值的修改通过SharedWorker通讯 SharedWorker是WebWorker的一种WebWorker可开启子进程执行…

JavaWeb - Maven

Maven apache旗下的一个来源项目,一款用于管理和构建java项目的工具,它基于项目对象模型(POM)的概念,通过一小段描述信息来管理项目的构建。 作用 安装 解压官网下载的压缩包 配置本地仓库,修改conf/se…

机器学习(西瓜书)第 3 章 线性模型

3.1 基本形式 线性模型要做的有两类任务:分类任务、回归任务 分类的核心就是求出一条直线w的参数,使得直线上方和直线下方分别属于两类不同的样本 回归就是用来拟合尽可能多的点的分布的方法,我们可以通过拟合的直线知道一个新样本的相关数…

day47——面向对象特征之继承

一、继承(inhert) 面向对象三大特征:封装、继承、多态 继承:所谓继承,是类与类之间的关系。就是基于一个已有的类,来创建出一个新类的过程叫做继承。主要提高代码的复用性。 1.1 继承的作用 1> 实现…

Windows conda常用方法

这里写目录标题 conda链接jupyter conda链接jupyter 列出当前所有环境: conda env list 创建新环境: conda create -n your_env_name pythonX.X(2.7、3.6、3.8等) 激活环境: conda activate your_env_name 链接jupyte…

VXLAN 为何采用UDP

VXLAN 简介 VXLAN是一种网络虚拟化技术,它通过在UDP数据包中封装MAC地址和IP信息,使得二层网络(如以太网)能够跨越三层网络(如IP网络)进行扩展。这种封装方式不仅支持TCP流量的传输,还能有效处…

SpringCloud开发实战(四):Feign远程调用

目录 SpringCloud开发实战(一):搭建SpringCloud框架 SpringCloud开发实战(二):通过RestTemplate实现远程调用 SpringCloud开发实战(三):集成Eureka注册中心 Feign简介 我…

机器学习(五) -- 监督学习(8) --神经网络1

机器学习系列文章目录及序言深度学习系列文章目录及序言 上篇:机器学习(五) -- 无监督学习(2) --降维2 下篇:机器学习(五) -- 监督学习(8) --神经网络2 前言…

基于SSM+MySQL的医院在线挂号系统

系统背景 在当前数字化转型浪潮的推动下,医疗服务行业正经历着前所未有的变革。随着人口老龄化的加剧、患者就医需求的日益增长以及医疗资源分布不均等问题的凸显,传统的就医模式已难以满足患者对于便捷、高效医疗服务的需求。因此,构建一套基…

设计模式 —— 单例模式

文章目录 一、单例模式1.1 单例模式定义1.2 单例模式的优点1.3 单例模式的缺点1.4 单例模式的使用场景 二、普通案例2.1 饿汉式单例模式(Eager Initialization Singleton)2.2 懒汉式单例模式(Lazy Initialization Singleton) 参考资料 本文源代码地址为 java-demos/singeleton-…

探索未来科技发展:芯片设计的创新之路

在当今这个日新月异的数字时代,芯片设计作为信息技术的核心驱动力,正以前所未有的速度推动着社会进步与产业升级。作为科技领域的璀璨明珠,芯片设计不仅关乎数据处理的速度与效率,更是人工智能、物联网、云计算等技术得以实现的基…

Docker 详解及详细配置讲解

Docker 简介 2008 年LXC(LinuX Contiainer)发布,但是没有行业标准,兼容性非常差 docker2013年首次发布,由Docker, Inc开发 什么是 Docker Docker是管理容器的引擎,为应用打包、部署平台,而非单纯的虚拟化技术&#xf…

不小心删除丢失了所有短信?如何在 iPhone 上查找和恢复误删除的短信

不小心删除了一条短信,或者丢失了所有短信?希望还未破灭,下面介绍如何在 iPhone 上查找和恢复已删除的短信。 短信通常都是非正式和无关紧要的,但短信中可能包含非常重要的信息。因此,如果您删除了一些短信以清理 iPh…

Python画笔案例-032 绘制螺旋扇子

1、绘制螺旋扇子 通过 python 的turtle 库绘螺旋扇子图,如下图: 2、实现代码 绘制螺旋扇子,以下为实现代码: """螺旋扇子.py """ import turtle from coloradd import * # 从coloradd命令导…

win12R2安装.NET Framework 3.5

一丶安装原因 因此插件的缺失, 有些软件或系统不支持安装. 二丶安装步骤 1丶下载.NET Framework 3.5 点击插件下载, 提取码: 1995, 下载完成之后解压到想要安装的位置上. 2丶打开 服务器管理器 3丶点击: 管理 -> 添加角色和功能 4丶点击下一步到服务器角色, 选择web服…

版本控制的核心:Git中的哈希与默克尔树解析

Git是最常用的代码版本控制工具。它帮助我们跟踪代码的更改、管理代码版本,同时保证代码库的完整性和安全性。我们知道 Git 中有一些基本的操作,比如commit、merge、rebase等,但这些操作的底层机制是如何实现的呢?哈希函数和默克尔…

计算机毕业设计Spark+PyTorch知识图谱房源推荐系统 房价预测系统 房源数据分析 房源可视化 房源大数据大屏 大数据毕业设计 机器学习

《SparkPyTorch知识图谱房源推荐系统》开题报告 一、选题背景与意义 1.1 选题背景 随着互联网的快速发展和大数据技术的广泛应用,房地产行业特别是房屋租赁市场迎来了前所未有的变革。房源信息的海量增长使得用户在寻找合适的房源时面临巨大挑战。传统的房源推荐…

电路分析 ---- 电平移位电路

1 电平移位电路 如图所示的电平移位电路,用于ADC的前级驱动,它将一个变化范围为-10V ~ 10V的输入信号,线性变化成0.048V ~ 4.048V的信号,以满足ADC的输入范围要求。 2 电路说明 V R E F V_{REF} VREF​为电压基准源&#xff0c…

开源软件指南

目录 什么是开源软件 开源软件的历史和哲学 什么是开源许可证 开源许可证的类型 ​编辑 开源合规性 版权和知识产权合规性 安全合规性 什么是开源软件政策 开源软件安全 库存和软件物料清单(SBOM) 依赖项更新 开源漏洞扫描 二进制存储库管理器 开源软件的当前趋势…