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

关于C语言零基础学习知识,小编有话说,各位看官敬请入下面的专栏世界:打怪升级之路——C语言之路_ankleless的博客-CSDN博客

Hi!冒险者😎,欢迎闯入 C 语言的奇幻异世界🌌!

我是 Anklelss🧑‍💻,和你一样的闯荡者~ 这是我的冒险笔记📖,里面有踩过的坑🕳️、攒的技能🌟、遇的惊喜🌈,希望能帮你少走弯路✨。

愿我们在代码山峦⛰️各自攀登,顶峰碰拳👊,共赏风景呀!🥳

1. 结构体

1.1 结构体类型的定义

在C语言中,结构体(struct)是一种自定义的数据类型,结构是一些值的集合,这些值被称为成员变量。结构体中每个成员变量可以是不同类型的。

1.2 结构体类型的声明

声明一个结构体我们需要使用语法元素struct,他的使用不需要包含特定的头文件。

大致声明模版如下:

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

那么我们如何用结构体去声明一个人的特征呢?

struct people
{char name[20];//姓名int age;//年龄int height;//身高char blood_type;//血型
};

1.3 结构体的初始化

有了上述的结构体people,那么我们应该如何去初始化他的数据呢?又应该怎么将他打印在屏幕上呢?

int main()
{struct people A = { "张三",18,182,'B' };struct people B = { "李四",22,190,'O' };printf("%s ", A.name);printf("%d ", A.age);printf("%d ", A.height);printf("%c\n", A.blood_type);//当我们知道一个结构体的首地址时//也可以用如下的方法进行打印struct people* p = &B;printf("%s ", p->name);printf("%d ", p->age);printf("%d ", p->height);printf("%c\n", p->blood_type);return 0;
}

. 点运算符)和 -> 箭头运算符)是用于访问结构体成员的两种操作符,核心作用是从结构体变量或结构体指针中获取/修改成员数据,但使用场景不同,如下是他们的语法要求:

.(点运算符)

作用:直接访问结构体变量成员

语法:结构体变量 成员

适用场景:当你拿到的是实实在在的结构体变量(不是指针)时,用.访问成员

->(箭头运算符)

作用:通过结构体指针访问成员

语法:结构体指针->成员名

适用场景:当你拿到的是结构体指针(存的是结构体变量的地址)时,用->访问成员

只有在变量初始化时,才能用字符串常量去赋值

1.4 匿名结构体

在C语言中,结构体用一种“特殊声明”,它是指匿名结构体的声明方式——即声明结构体时不指定结构体名,直接定义成员和变量。(也叫不完全声明

匿名结构体的核心是省略结构体名,语法如下:

// 形式1:声明时直接定义变量
struct {数据类型 成员1;数据类型 成员2;// ... 其他成员
} 变量名1, 变量名2;  // 只能在此处定义变量// 形式2:结合 typedef 定义类型别名(常用)
typedef struct {数据类型 成员1;数据类型 成员2;
} 类型别名;  // 后续可通过别名定义变量

通常,他可以直接声明变量(一次性使用),也可以结合typedef定义类型别名(常用方式)

:直接声明变量无法重复定义变量,只有结合typedef,后续才可以反复用别名定义变量,实用性更强。

typedef 和 结构体在数据结构中的链表知识板块有更多复杂真实的应用

1.4.1 结构体的自引用

在结构体中存在一种错误的自引用方式,他们的代码表现形式如下:

1. 如下的代码形式导致了无限大的结构体变量,这是不合理的

struct Node
{int data;struct Node next;
//类似递归,但没有趋近条件
//导致了占用无限大的内存空间
};

2. 如下的代码形式提前使用了typedef的类型别名,这是不允许的

typedef struct
{int data;Node* next;//提前使用了未被定义的指针类型
}Node;

如下是正确的自引用形式,这在链表中十分重要。

typedef struct Node
{int data;struct Node* next;//是指针,而不是结构体本身
}Node;

1.5 结构体的内存对齐

我们应该如何计算结构体的内存大小呢?简单的相交?

根据上述的疑问,结构体的内存对齐提供了正确的答案

1.5.1 对齐规则

结构体的对齐规则如下:

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

offsetof可以计算不同成员的偏移量)

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

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

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

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

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

我们以下面的代码为例:

struct num
{char a;int b;char c;float a;
};

如下是该结构体的内存大小计算过程:

结构体的内存对齐,是一种拿空间换时间的存储方式

1.5.2 修改默认对齐数

#pragma这个预处理指令,可以改变编译器的默认对齐数,具体用例如下:

#include <stdio.h>
#pragma pack(1)//设置默认对⻬数为1
struct S
{char c1;int i;char c2;
};
#pragma pack()//取消设置的对⻬数,还原为默认
int main()
{//输出的结果是什么?printf("%d\n", sizeof(struct S));return 0;
}

结构体在对齐不合适的时候,我们可以更改默认对齐数

1.6 结构体传参

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;
}

上述代码中,print1相当于在内存空间中拷贝了一份结构体s,会增加程序运行时的时间和空间负担,print2不会有这种缺陷,并且传指针的方式也可以对结构体内部的元素进行相对的修改

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

———————————————————————————————————————————

2. 联合体

2.1 联合体类型的定义

在C语言中,联合体是一种特殊的数据结构,他允许在同一块内存空间中存储不同类型的数据,但同一时刻只能存储其中一种类型的数据(即所有成员共享同一段内存)

联想记忆:像电影中人格分裂的角色,就和联合体特征一致,共用一具身体但是人格多样,且一次只能出现一种人格

2.2 联合体类型的声明

联合体也叫做共用体,给一个成员赋值时,会影响其他成员的值。声明时需使用union

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

2.3 联合体的特点和内存计算

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

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

#include <stdio.h>
union Un1
{char c[5];int i;
};
union Un2
{short c[7];int i;
};
int main()
{//下⾯输出的结果是什么?printf("%d\n", sizeof(union Un1));printf("%d\n", sizeof(union Un2));return 0;
}

我们得到UN1的大小为8个字节(最大对齐数为4);UN2的大小为16个字节(最大对齐数为4)。

以UN2为例,最大成员所需内存大小为14字节,但联合体中最大对齐数为4, 14不是4的整数倍,根据规则,需要扩展到16个字节大小。

3. 枚举

3.1 枚举类型的定义

在C语言中,枚举是一种用户定义的数据类型,用于为整数常量指定有意义的名称,使代码更具有可读性和可维护性。枚举类型的变量只能取枚举中定义的常量值

3.2 枚举类型的声明

枚举顾名思义就是⼀⼀列举,他的声明需要用到enum,示例如下:
enum Day//星期
{Mon,Tues,Wed,Thur,Fri,Sat,Sun
};

枚举类型的变量本质上存储的是整数,枚举常量只是这些整数的“别名”,上述声明中的枚举常量遵循默认值规则,即:

enum Num {A,  // 默认值为 0B,  // 默认值为 1(前一个值 +1)C   // 默认值为 2(前一个值 +1)
};

同样的,我们也可以显式显式指定值:

enum Status {OK = 0,        // 显式指定为 0ERROR = -1,    // 显式指定为 -1WARN,          // 自动为 0(ERROR 的值 -1 +1 = 0)INFO = 5,      // 显式指定为 5DEBUG          // 自动为 6(INFO 的值 5 +1 = 6)
};

手动为枚举常量指定任意的整数(正数、负数、零均可),后续未指定值的常量会在前一个常量的基础上+1

在枚举类型中,不同的枚举常量可以被指定为相同的值,但这种方法会降低代码可读性

3.3 枚举类型的优点

在C语言中,我们知道#define也可以定义常量,他是一种文本替换,那为什么非要使用枚举呢?他到底有什么特别之处呢?

枚举的优点:

1. 增加代码的可读性和可维护性

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

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

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

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

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

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

相关文章

海康威视摄像头实时推流到阿里云公网服务器(Windows + FFmpeg + nginx-rtmp)

海康威视摄像头实时推流到阿里云公网服务器&#xff08;Windows FFmpeg nginx-rtmp1. 步骤总览2. 阿里云 ECS&#xff08;Linux&#xff09;配置2.1 开放端口2.2 安装 nginx-rtmp3. Windows 电脑端配置3.1 安装 FFmpeg3.1.1 官网/镜像下载&#xff1a;3.1.2 解压后将 bin 目录…

基础网络网路层——IPV4地址

在IP网络上&#xff0c;如果用户要将一台计算机连接到Internet上&#xff0c;就需要向因特网服务提供方ISP&#xff08;Internet Service Provider&#xff09;申请一个IP地址。IP地址是在计算机网络中被用来唯一标识一台设备的一组数字。IPv4地址由32位二进制数值组成&#xf…

技术速递|GPT-5 正式上线 Azure AI Foundry

AI 应用正在经历一场深刻变革——对企业来说&#xff0c;仅仅“能聊天”早已不够&#xff0c;生成内容、逻辑推理、落地生产&#xff0c;这些才是新时代对 AI 能力的真正考验。 今天&#xff0c;我们非常激动地宣布&#xff0c;OpenAI 最新旗舰大模型 GPT-5 正式上线 Azure AI …

Logistic Regression|逻辑回归

----------------------------------------------------------------------------------------------- 这是我在我的网站中截取的文章&#xff0c;有更多的文章欢迎来访问我自己的博客网站rn.berlinlian.cn&#xff0c;这里还有很多有关计算机的知识&#xff0c;欢迎进行留言或…

三极管在电路中的应用

1、信号放大&#xff08;电压放大&#xff09; 应用场景 &#xff1a;麦克风声音放大、耳机驱动、广播信号接收等音频设备 原理解析 &#xff1a; 想象三极管如同一个精准的水龙头&#xff1a; 基极&#xff08;B&#xff09;电流如同拧动阀门的微弱力量&#xff08;输入信号&a…

Redis 事务机制

文章目录一、什么是事务&#xff1f;二、事务相关操作总体认识基本操作流程watch 操作演示watch 原理一、什么是事务&#xff1f; Redis 的事务和 MySQL 的事务概念上是类似的. 都是把⼀系列操作绑定成⼀组. 让这⼀组能够批量执⾏. Redis 的事务和 MySQL 事务的区别&#xff1…

Mybatis学习之自定义映射resultMap(七)

这里写目录标题一、准备工作1、新建maven工程2、准备两张表3、建立mapper、pojo、映射文件mapper接口pojoxxxMapper.xml二、resultMap处理字段和属性的映射关系1、用起别名的方式保证字段名与属性名一致2、逐一设置resultMap映射关系3、配置mapUnderscoreToCamelCase三、多对一…

数学学习 | 高数、线代、概率论及数理统计荐书

注&#xff1a;本文为 “数学学习书目推荐” 相关合辑。 略作重排&#xff0c;如有内容异常&#xff0c;请看原文。 高等数学、线性代数及概率论与数理统计领域推荐书目 西湖边的卡夫卡 编辑于 2023-09-19 13:26 7495 人赞同了该回答 数学具有内在的美学属性&#xff0c;但并非…

【LLM实战|langgraph】langgrpah基础

every blog every motto: You can do more than you think. https://blog.csdn.net/weixin_39190382?typeblog 0. 前言 langgraph 基础 1. Chatbot实现 # !pip install langchain # !pip install langgraphfrom typing import Annotatedfrom typing_extensions import Typ…

大疆无人机使用eport连接Jetson主板实现目标检测

所需硬件设备如下&#xff1a; 实现原理&#xff1a; 视频流获取&#xff1a;从大疆无人机获取实时视频流。数据传输&#xff1a;将视频流传输至 Jetson 平台。目标检测处理&#xff1a;在 Jetson 上运行目标检测算法对传入的视频帧进行分析 EPort开发套件 大疆官网给出了…

Typora激活与使用

Typora下载 下载地址&#xff1a;Typora 官方中文站 Typora&#xff08;1.9.5及其以前的版本&#xff09; 工具&#xff1a;待补充 流程 1.解压工具 2.将license-gen.exe、node_inject.exe两个文件放于typora安装目录下 3.在typora安装目录下运行cmd&#xff08;可以打开…

图片拆分工具,自定义宫格切割

软件介绍 今天推荐一款实用的图像处理工具——lmage Splitter&#xff0c;支持图像拆分与格式互转功能&#xff0c;无广告干扰&#xff0c;操作简单流畅&#xff0c;满足多样化图片编辑需求。 软件优势 该工具为绿色版设计&#xff0c;无需安装即可直接运行&#xff0c;下载…

23种设计模式解析--创建型模式

创建型模式&#xff08;造物主的智慧&#xff09; 单例模式 模式定义 单例模式&#xff08;Singleton&#xff09;确保一个类仅有一个实例&#xff0c;并提供该实例的全局访问点。核心思想是通过私有化构造函数和静态成员实现受控的对象创建。核心实现要点 私有构造函数&#x…

全面解析软件工程形式化说明技术

一、形式化说明技术概述&#xff1a;从模糊到精确的跨越 在软件工程的发展历程中&#xff0c;需求说明技术始终是确保软件系统成功开发的关键环节。从早期依赖自然语言的非形式化描述&#xff0c;到如今基于数学和逻辑的形式化方法&#xff0c;这一领域经历了从模糊到精确的深…

百度网盘自动启动如何关闭,关闭智能看图

#某度软件引起的奔溃#在日常办公中&#xff0c;有时候双击图片&#xff0c;会自动打开了某度的网盘&#xff0c;很奇怪莫名其妙的为什么会关闭网盘后又自动打开了。如何发现是某度的牛虻软件在搞鬼的&#xff1f;我右键图片&#xff0c;选择打开方式&#xff0c;发现有“智能看…

疏老师-python训练营-Day40训练和测试的规范写法

浙大疏锦行 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#xff1a;仔细学习下测…

【重磅发布】flutter_chen_keyboard -专注于键盘相关功能

flutter_chen_keyboard 一个功能强大且易于使用的 Flutter 键盘增强库&#xff0c;专为提升移动应用的键盘交互体验而设计。 &#x1f4d6; 库简介 flutter_chen_keyboard 是一个专注于键盘相关功能的 Flutter 工具库&#xff0c;旨在为开发者提供更流畅、更智能的键盘交互解决…

idea设置注释--带日期和作者和描述

最终效果 在File Header中添加如下内容&#xff1a; /*** author ${USER}* date ${DATE} ${TIME}* description ${DESCRIPTION}*/${USER}&#xff1a;IDEA 里设置的用户名 ${DATE}&#xff1a;当前日期 ${TIME}&#xff1a;当前时间 可以加自定义变量&#xff0c;比如 ${DESCRI…

【Linux】Socket编程——UDP版

&#x1f4dd;前言&#xff1a; 这篇文章我们来讲讲Linux——udpsocket &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;Linux &#x1f380;CSDN主页 愚润求学 &#x1f304;其他专栏&#xff1a;C学习笔记&#xff0c;C语言入门基础&#…

RabbitMQ面试精讲 Day 14:Federation插件与数据同步

【RabbitMQ面试精讲 Day 14】Federation插件与数据同步 开篇 欢迎来到"RabbitMQ面试精讲"系列第14天&#xff0c;今天我们将深入探讨RabbitMQ Federation插件与跨集群数据同步机制。在分布式系统架构中&#xff0c;如何实现消息队列集群间的数据同步是确保业务连续…