自定义类型上

简介: 我们之前学过很多种类型,有int、char、float、double等等,这些都是属于既定类型,那么自定义类型顾名思义就是可以由你自己来定义的类型,比如我们接下来要讲的结构体、联合体、枚举都属于自定义类型。

目录

什么是自定义类型

结构体

结构体的声明

常规结构体的声明形式

特殊的结构体声明形式

匿名结构体:
匿名结构体的重命名:

注意事项:

结构体的自引用

什么是结构体的自引用

结构体变量的定义与初始化

方法一:

方法二:

方法三:
结构体内存对齐

结构体传参

位段

枚举

枚举的声明

枚举的优点

枚举的使用

联合体

联合体的声明

大小的特点:

大小的计算:


什么是自定义类型


我们之前学过很多种类型,有int、char、float、double等等,这些都是属于既定类型,那么自定义类型顾名思义就是可以由你自己来定义的类型,比如我们接下来要讲的结构体、联合体、枚举都属于自定义类型。


结构体


首先我们来介绍结构体。


结构体的字面上的意思就是一个成结构的体系,因此它当然离不开组成它的部分了,而这些部分,就是结构体里边各种类型的成员。

结构体的声明

常规结构体的声明形式


67c6b0f996844d8f88bd513c2e435cf0.png

我们这里创建了一个以学生信息为组成部分的结构体,我们可以看到一个简单的结构体是由哪些方面组成的。


①首先结构体的创建是由这样一个形式开始的,即struct+结构体类型名,而这里,结构体类型名就是stu(这个名字是自定义的,可以叫a也可以叫b,由于我们要创建一个关于学生的结构体,所以我选择了stu,即student的缩写,作为类型名。而这个特点就是我们标题所说的自定义类型的体现)


②接着我们还可以看到,在这个结构体的内部,包含了多个信息,即学生的姓名、年龄、班级、学号(如果需要的话,你可以再多加些信息,比如年级、性别等等)。这些信息的类型有char、int。当然,如果你愿意,你也可以在里边创建其他类型,比如double、float,甚至还可以再创建一个struct+类型名,形成结构体的嵌套,而这是后话了。


③细心的你可能还发现了,在这个结构体的最后,多出来个分号,而这个分号是不能缺少的,这似乎表明了在 };之间还可以有东西放进去,没错,在结构体的最后,还有结构体的变量,如图


初学易错点:

有人可能会觉得奇怪,为什么在创建结构体的开头已经有了stu,后面却又可以额外加s1,s2,s3。之所以会有这样的困惑,是因为他们习惯性地把我们之前创建变量的直观思维代入到了结构体上,简单来说就是,我们之前创建变量的形式是这样的:int a 即:类型+变量名,而我们又很容易把这样的形式套到结构体上,从而以为struct stu也是类型+变量名,但实际上这里的stu才是类型,也就是说这里stu的地位其实就相当于int,那结构体里边的变量在哪呢?那很显然就是那些加在后面的s1,s2,s3.


但是话说回来,像我们开始时如下图这样创建的时候:


7c098c74d4ae4163839989b70baf9fdb.png


这里并没有设定像s1,s2,s3这样的变量,而是什么都没有,};之间只是空着,那么这样是否违背了语法呢?其实并没有。 如图:

88d10a21851943b28fcb4a12bdd2b10c.png


这里我们可以很直观明了地看到,像s1,s2,s3这样的变量可以之后创建。这说明在};之间先不创建变量,在后面需要时再另外创建变量是符合语法的。但这里有着全局变量与局部变量的区别,使用时要特别注意这个细节。


特殊的结构体声明形式

匿名结构体:

struct
{
int a ;
char b ;
float c ;
} x ;
struct
{
int a ;
char b ;
float c ;
} a [ 20 ], * p ;

在这里,结构体的声明省略了类型名,并且这样做是符合语法的,这样的结构体叫做匿名结构体,由于没有类型名,它在之后不能再用来创建局部变量,所以这样的结构体一般只能作为一次性消耗品。


匿名结构体的重命名:

3fe4758ee5ac445a90c4fb92e8b17a75.png


如图,利用typedef可以将匿名结构体重新命名,使其可以利用新的类型名去创建变量,但是要注意,虽然同样是放在};之间,但上图中的stu是类型名!

注意事项:

1)在创建匿名结构体的时候,不能再像创建常规结构体那样,把变量名省略,像这样:

986029ba7a7e4d6b80f1c6f52c5cb010.png



虽然这样的创建方式在编译时不会报错(可能会警告),但是这样的结构体是没有用的!因为在创建时,它本身省略掉了类型名,而现在如果还要把变量名省略,那么它在之后也不可能再创建变量了,也就是不可能像下图这样:

e8044a8b6fa64396826a893be115da4f.png


道理很简单,虽然这张图里在创建结构体时省去了变量名,但是仍然可以凭借stu这个类型名在之后创建局部变量s1,s2,s3。但这对于匿名结构体来说却是不可能的,因为它连类型名也没有。


关于一些错误用法


一般来说,不同类型的结构体如果设定了相同的变量名,那么就会出现重定义,从而导致编译器报错,就像这样:

28ebffdd6fb476b5a74a74fc20ff499b.png

f86bff8beb1daf608e6beba2b5308350.png


但是匿名结构体并没有定义类型名,那是不是就可以看作同一类型的结构体,从而定义相同的变量了呢?


答案是不行!


结构体的自引用

什么是结构体的自引用

结构体的自引用,简单来说,就是在结构体的内部,包含一个和该结构体类型相同的成员。


(在结构体内部再创建一个结构体,并且两者要类型一致)


浅谈单链表

为什么要提到链表呢?因为最能直观体现出结构体自引用的就是单链表,我们不要被这个抽象的表达给唬住,单链表的原理十分简单。


我们在上文有说,结构体之内其实可以再创建结构体,利用这个原理,搭配指针,我们就可以实现链表的创建。


如图:



6d748c14acf74987a906a1bcee6e7f8a.png


4a8c86f3f0ef4825870dd8a8d0e1b5bf.png

结构体变量的定义与初始化

方法一:

c804d610727a9a795551753720d612cd.png

方法二:

40004ca3b9fb5e0127e8a6cb88c9db89.png

方法三:

be5cb146dc8968512449a76820c5b4ab.png

结构体内存对齐

一般情况:

本环节是理解结构体的储存原理的关键,掌握后你就会明白结构体大小计算的规律。在开始之前,请大家先思考一下,下图输出的结果会是什么?



我想很多人的回答通常都会是:6 6 13(char、int、double的字节大小分别为1 4 8)


但是我们运行一下,出来的结果却是这样:



很反直觉对吧?要搞清楚这个问题,我们就要了解结构体内存对齐这个重要性质。其实这个知识点并不复杂,针对上图的练习3,下面一张图带你掌握:286de56b4a7e491185aadf136413cfbd.png


d65711f397da4471870e693aa795be96.png



cd00010b938f41a88ec93e4f54632af3.png



小技巧:让占用空间小的成员尽量集中在一起,这样做可以在节省时间的同时最大限度地减小空间的浪费


修改默认对齐数

#include <stdio.h>
#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 ;
}

结论: 


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


相关文章
|
7月前
|
存储 编解码 数据可视化
三维基因组:diffHic 差异分析
三维基因组:diffHic 差异分析
三维基因组:diffHic 差异分析
|
10月前
|
搜索推荐 Java 关系型数据库
MCMS:Star 28.1k,还在为CMS系统发愁?这款开源神器让内容管理变得像搭积木一样简单!
MCMS(MingSoft内容管理系统)是一个基于Java EE的开源CMS,以其模块化设计、响应式布局和SEO友好等特点著称。它支持多种数据库,提供强大的安全性和多语言支持,适用于企业官网、电子商务平台、个人博客和知识管理等多种场景。MCMS帮助用户快速构建和管理个性化网站,满足不同需求。项目地址:[https://gitee.com/mingSoft/MCMS](https://gitee.com/mingSoft/MCMS)
391 18
|
8月前
|
存储 Oracle 安全
推荐的开源软件中小企业行业数字化场景
在数字化转型中,中小企业常遇成本、技术和安全挑战。Websoft9依托开源软件,提供自主可控的解决方案。文章以十大核心场景为例,如制造业用Odoo ERP降低成本、K3s优化产线监控;金融领域以PostgreSQL替代Oracle节省费用;医疗行业借助Nextcloud保障数据隐私;零售业通过WordPress搭建独立站减少开支等,结合真实案例解析开源技术如何驱动业务创新与增长。
258 0
|
机器学习/深度学习 人工智能 数据可视化
人工智能在图形学领域的研究热点有哪些?
AIGC:通过生成对抗网络(GAN)、变分自编码器(VAE)及其变体等技术,能够根据用户输入的文字描述、草图等生成高质量、高分辨率的图像,在艺术创作、游戏开发、广告设计等领域应用广泛。如OpenAI的DALL-E、Stable Diffusion等模型,可生成风格各异、内容丰富的图像,为创作者提供灵感和素材.
406 59
|
12月前
|
人工智能 自然语言处理 小程序
魔搭社区每周速递(12.15-12.21)
🙋魔搭ModelScope本期社区进展:📟1914个模型,📁58个数据集,🎨78个创新应用,📄 8篇内容
417 4
魔搭社区每周速递(12.15-12.21)
|
机器学习/深度学习 人工智能 前端开发
【AI系统】计算图的控制流实现
计算图作为有向无环图(DAG),能够抽象神经网络模型,但在编程中遇到控制流语句(如if、else、while、for)时,如何表示成为难题。引入控制流后,开发者可构建更复杂的模型结构,但部署含控制流的模型至不支持Python的设备上较为困难。目前,PyTorch仅支持Python控制流,而TensorFlow通过引入控制流原语来解决此问题。计算图的动态与静态实现各有优劣,动态图易于调试,静态图利于优化。
314 5
【AI系统】计算图的控制流实现
|
9月前
|
人工智能 搜索推荐 大数据
大家都在怎么用AI?2024趋势报告
大家都在怎么用AI?2024趋势报告
|
供应链 安全 数据挖掘
深度剖析区块链技术在金融科技领域的创新应用与挑战####
本文旨在探讨区块链技术于金融科技(FinTech)领域的革新性应用,分析其如何重塑传统金融服务模式,并深入剖析面临的技术与监管挑战。通过案例研究与数据分析,揭示区块链在提升金融效率、增强安全性及促进金融包容性方面的潜力,同时强调构建健全的法律法规框架与技术创新之间的平衡对于推动行业健康发展的重要性。本文不涉及具体代码实现或技术细节,而是聚焦于区块链应用的战略意义与实践挑战。 ####
|
Python
在Python中,`try...except`语句用于捕获和处理程序运行时的异常
在Python中,`try...except`语句用于捕获和处理程序运行时的异常
359 5
|
前端开发
create-react-app 如何使用 less/sass 和 react-css-modules?
本文详细介绍了在 create-react-app 项目中如何使用 less/sass 和 react-css-modules 来管理和应用样式。首先,通过安装相应依赖并配置 webpack 支持 less/sass;接着,介绍如何使用这些预处理器编写样式;最后,讲解了如何配置和使用 react-css-modules 实现样式的模块化管理,以及如何结合使用 less/sass 和 react-css-modules 提高开发效率和代码质量。
315 3