【C语言进阶(8)】自定义数据类型1:结构体

news2024/11/25 21:16:42

文章目录

  • 前言
  • Ⅰ 结构体的声明和定义
    • ⒈结构体声明
    • ⒉结构体定义
    • ⒊特殊的声明
  • Ⅱ 结构体的自引用
  • Ⅲ 结构体初始化
  • Ⅳ 访问结构体成员
  • Ⅴ 结构体内存对齐
    • ⒈结构体内存对齐规则
    • ⒉分析结构体大小
    • ⒊嵌套结构体内存大小
    • ⒋内存对齐存在的原因
  • Ⅵ 修改默认对齐数
  • Ⅶ 结构体传参

前言

  • C 语言本身提供了一些基础的内置数据类型,例如:
char		//字符型数据
short		//短整型数据
int 		//整型数据
long		//长整型数据
long long	//更长的整型数据
float		//单精度浮点型数据
double		//双精度浮点型数据
......
  • 但是很多时候需要描述的对象并没有那么简单,这些对象不是简单的一个 int 或者 char 就能完整描述出来的。
  • 因为当我们描述这些复杂对象的时候,就像自定义函数一样,也会有自定义数据类型

结构的基础知识

  • 结构是一些值的集合,这些值称为成员变量
  • 结构的每个成员可以是不同类型的变量

Ⅰ 结构体的声明和定义

⒈结构体声明

1. 语法格式

struct 结构体名称
{
	结构体成员 1;
	结构体成员 2;
	结构体成员 3;
	......
	结构体成员 n;
};

2. 结构体的嵌套

  • 在声明结构体时,结构体成员即可以是任何一种基本的数据类型,也可以是另一个结构体,如果是后者,那么就相当于是结构体的嵌套。

3. 声明结构体的位置

  • 结构体声明即可以在所有函数的外面,也可以单独放在一个函数内部使用。如果是后者,则该结构体就指针在该函数中被定义。

4. 声明结构体实例

  • 一本书的结构体声明应该是这样的:
struct Book
{
	char title[120];
	char author[40];
	float price;
	unsigned int date;
	char publisher[40];
};

⒉结构体定义

  • 根据自定义的结构体类型来创建一个结构体变量,称为结构体的定义。
  • 结构体声明只是进行一个框架的描述,定义一个真正的结构体类型变量之前,它并不会在内存中分配空间存储数据。

1. 定义结构体变量的语法

struct 结构体名称 结构体变量名;

2. 定义结构体变量的位置

  1. 在声明时定义结构体变量:在声明结构体同时定义一个结构体变量,此时的结构体变量就是一个全局变量

  2. 在函数内部定义结构体变量:在函数内部根据声明的结构体类型定义一个结构体变量,此时的结构体变量就是一个局部变量

struct Book
{
	char title[120];
	char author[40];
	float price;
}book;					//1. 此时 book 被定义为全局变量

int main()				//别把 main 函数不当函数
{
	struct Book book;	//2. 此时 book 被定义为局部变量
	......

	return 0;
}

⒊特殊的声明

  • 在声明结构体的时候,也可以选择进行不完全声明。即省略结构体类型名。

匿名结构体类型

  • (只能在声明时定义结构体变量)(该结构体变量只能用一次)
struct 
{
	char title[120];
	char author[40];
	float price;
}book;//book 这个结构体变量只能被使用一次

Ⅱ 结构体的自引用

  • 结构体自己找到一个与自己同类型的另一个数据,称为结构体的自引用。
  • 在数据结构中的链表中就会使用这种方式。

链表的基础知识

  • 在内存中,并不是所有相同类型的数据都是连续存放在内存中的。
  • 有时想要找到那些不知道藏在那个角落里的数据就要使用链表的形式了。
  • 链表:除了链尾结点外,每个结点都包含着指向下一个同类型结点的地址。

在这里插入图片描述

链表结点的设计

struct Node
{
	int data;			//数据域:该结点本身应该存储的数据
	struct Node* next;	//指针域:存储下一个结点的地址
};

Ⅲ 结构体初始化

  • 在定义一个变量或数组的时候可以对其进行初始化。
int a = 520;
int arr = { 5,2,0 };
  • 同样的,在定义结构体变量的时候也可以对其进行初始化。
struct Book
{
	char title[128];
	char author[40];
	float price;
};

int main()
{
	struct Book book = { "《C primer plus》","史蒂芬·普拉达",108};

	return 0;
}

结构体嵌套初始化

  • 当结构体 A 中包含另一个结构体 B 时,对其 B 要在对 A 初始化的大括号内嵌套一个大括号用以初始化 B。
struct Name
{
	char title[128];
	char author[40];
};

struct Book
{
	struct Name name;
	float price;
};

int main()
{
	struct Book book = { {"《C primer plus》","史蒂芬·普拉达"},108 };

	return 0;
}

Ⅳ 访问结构体成员

  • 访问结构体的内容有两种方式:
    1. 结构体变量 . 结构体成员:结构体变量使用 " . " 操作符访问结构体成员的内容。
    2. 结构体指针 -> 结构体成员:指向结构体变量的结构体指针使用 " -> " 操作符访问结构体成员的内容。

在这里插入图片描述

Ⅴ 结构体内存对齐

计算结构体的大小

  • 结构体的大小和结构体内的每个结构体成员的类型有关。
  • 但是不同数据类型的结构体成员在结构体内的位置也影响着整个结构体的大小。
  • 结构体的大小并不是把所有结构体成员的大小加起来
struct S1
{
	char a;	//1 字节
	int  b;	//4 字节
	char c;	//1 字节
};

struct S2
{
	char a;	//1 字节
	char b;	//1 字节
	int  c;	//4 字节
};

在这里插入图片描述

  • S1 和 S2 的结构体成员都是相同的,只是成员位置的不同就直接导致结构体的大小相差了 4 个字节。
  • 结果不一样的原因是编译器对结构体的成员进行了对齐,说白了,对齐是为了让 CPU 可以更快的读取和处理数据。

⒈结构体内存对齐规则

  1. 第一个结构体成员位于结构通变量偏移量为 0 的位置。
    • 偏移量
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址。
  3. 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到字节的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。

偏移量

  • 开辟空间时,某个字节的地址相对于起始地址所偏移的字节个数称之为偏移量。例如:
    • 第一个字节的的地址相较于起始位置的地址,一个字节都没偏移,所以第一个字节处为偏移量 0。
    • 第二个字节的地址相较于起始位置的地址,偏移了一个字节,第二个字节的空间为偏移量 1 处。

对齐数

  • 编辑器默认(VS 中的对齐数默认为 8)的一个对齐数与该成员大小的较小值。例如:
    • int 变量的对齐数为 4,比默认对齐数 8 小,所以此时的对齐数为 4。
    • char 变量的对齐数为 1,比默认对齐数 8 小,所以此时的对齐数为 1。
  • 其他编译器上,对齐数就是变量的自身大小。

⒉分析结构体大小

在这里插入图片描述

1. 分析 s1 的大小

在这里插入图片描述

2. 分析 s2 的大小

在这里插入图片描述

⒊嵌套结构体内存大小

结构体嵌套时的内存对齐规则

  1. 如果嵌套了结构体的情况,嵌套的结构体对齐到字节的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(包含嵌套结构体的对齐数)的整数倍。
struct S3
{
	double a;		//8 字节
	char   b;		//1 字节
	int    c;		//4 字节
};

struct S4
{
	char      d;	//1 字节
	struct S3 s3;	//16字节
	double    e;	//8 字节
};

在这里插入图片描述

  • s3 的大小看完 s1 和 s2 的分析之后后应该能自己分析出来,就不过多赘述了。
  • 主要是分析嵌套了 S3 的 s4 的大小是怎么来的。

分析 s4 的大小

在这里插入图片描述

⒋内存对齐存在的原因

1. 平台原因(移植原因)

  • 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2 性能原因

  • 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
  • 因为为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需一次访问。

如何同时满足(内存对齐,节省空间)

  • 设计结构体的时候,将占用空间小的成员放在一起

在这里插入图片描述

Ⅵ 修改默认对齐数

  • 使用 #pragma 这个预处理指令,可以修改默认对齐数。
struct S		//此时默认对齐数为 8
{
	int		i;	//偏移量 0 ~ 3
	double	d;	//偏移量 8 ~ 15
};

int main()
{
	printf("%d\n", sizeof(struct S));	//16

	return 0;
}

1. 修改默认对齐数

#pragma pack(4)	//将默认对齐数改为 4
struct S		
{
	int		i;	//偏移量 0 ~ 3
	double	d;	//偏移量 4 ~ 11
};
#pragma pack()	//将默认对齐数回复成 8

int main()
{
	printf("%d\n", sizeof(struct S));	//12

	return 0;
}

在这里插入图片描述

2. 取消内存对齐

  • 将默认对齐数改为 1,这样不管是什么类型数据的对齐数和默认对齐数比较,都是默认对齐数小,就会直接使用默认对齐数为当前对齐数。
#pragma pack(1)	//只要是 1 的倍数都可以存放
struct S		
{
	char a;//0
	int  b;//1 ~ 4
	char c;//5
};
#pragma pack()	//将默认对齐数回复成 8

int main()
{
	printf("%d\n", sizeof(struct S));//6

	return 0;
}

Ⅶ 结构体传参

  • 结构体传参分为(传结构体变量)和(传结构体地址)。
  • 结构体传参时,尽量选择传址调用(传结构体地址)
struct Book
{
	char title[128];
	char author[40];
};

void print1(struct Book book)
{
	printf("|-----传结构体变量-----|\n");
	printf("书名:%s\n", book.title);
	printf("作者:%s\n", book.author);
	printf("|----------------------|\n");
}

void print2(struct Book* p)
{
	printf("|-----传结构体地址-----|\n");
	printf("书名:%s\n", p->title);
	printf("作者:%s\n", p->author);
	printf("|----------------------|\n");
}

int main()
{
	struct Book book = { "《C primer plus》","史蒂芬·普拉达"};

	print1(book); //传结构体变量
	print2(&book);//传结构体地址

	return 0;
}

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

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

相关文章

嵌入式系统存储体系

一、存储系统概述 主要分为三种:高速缓存(cache)、主存和外存。 二、高速缓存Cache 高速缓冲存储器中存放的是当前使用得最多得程序代码和数据,即主存中部分内容的副本,其本身无自己的地址空间。在嵌入式系统中Cac…

视频怎么变成动态gif图?一个方法轻松转换

怎么将视频转换成gif动态图片呢?大家在日常看电影、电视剧,刷短视频的时候想要将其做成gif表情包时,应该如何操作呢?这时候,给大家分享一款操作简单无需下载的视频gif转换(https://www.gif.cn/)…

ubuntu22安装和部署Kettle8.2

前提 kettle是纯java编写的etl开源工具,目前kettle7和kettle8都需要java8或者以上才能正常运行。所以运行kettle前先检查java环境是否正确配置,java版本是否是8或者以上。 kettle安装 1、创建kettle目录,并将kettle的zip包解压到kettle目…

Linux 系统运维工具之 OpenLMI

一、前要 OpenLMI(全称 Open Linux Management Infrastructure)即开放式的 Linux 管理基础架构。OpenLMI 是一个开源项目,用于管理 Linux 系统管理的通用基础架构。它建立在现有工具基础上,充当抽象层,以便向系统管理…

CTF-XXE(持续更新,欢迎分享更多相关知识点的题目)

知识 实例 BUU [PHP]XXE 进来看到 然后一起看 Write BUU XXE COURSE 1 进来看到 一起看 write NSS [NCTF2019]Fake XML cookbook 反正是XXE 直接整 write [NCTF 2019]True XML cookbook 不整花里胡哨,解题在最下面 write 与博主不同,我通过…

【C++多线程】C++11互斥锁和条件变量实现生产者消费者模型

先看几个问题,第三个问题可以先看代码然后再理解 Q1:临界区在哪 A1: 队列中元素在「生产者生产(push)」和「消费者消费(pop)」时就是临界区 Q2:同步操作在哪 A2: 很显然,队列只有…

在kaggle中用GPU使用CGAN生成指定mnist手写数字

文章目录 1项目介绍2参考文章3代码的实现过程及对代码的详细解析独热编码定义生成器定义判别器打印我们的引导信息模型训练迭代过程中生成的图片损失函数的变化 4总结5 模型相关的文件 1项目介绍 在GAN的基础上进行有条件的引导生成图片cgan 2参考文章 GAN实战之Pytorch 使用…

android framework之Applicataion启动流程分析

Application启动流程分析 启动方式一:通过Launcher启动app 启动方式二:在某一个app里启动第二个app的Activity. 以上两种方式均可触发app进程的启动。但无论哪种方式,最终通过通过调用AMS的startActivity()来启动application的。 根据上图…

家政服务行业搭建小程序的实用技巧分享

随着移动互联网的发展,小程序成为了各行各业的新宠。对于家政服务行业来说,搭建一个小程序商城可以极大地提升服务的便捷性和用户体验,同时也能提高企业的竞争力。本文将分享家政服务行业搭建小程序的实用技巧,帮助您顺利创建属于…

利用深度蛋白质序列嵌入方法通过 Siamese neural network 对 virus-host PPIs 进行精准预测【Patterns,2022】

研究背景: 病毒感染可以导致多种组织特异性损伤,所以 virus-host PPIs 的预测有助于新的治疗方法的研究;目前已有的一些 virus-host PPIs 鉴定或预测方法效果有限(传统实验方法费时费力、计算方法要么基于蛋白结构或基因&#xff…

SAP-FI-会计凭字段替代OBBH

会计凭证替代OBBH 业务:文本必须等于某个字段的值,例如凭证日期 关闭确认功能,输入OBBH 双击“替代”进入功能配置,或者用GGB1,用GGB1的功能更多。 点击行项目,点击“新建替换”保存 点击新建YXL7331,点击…

删除命名空间一直处于Terminating

删除命名空间一直处于Terminating 通常删除命名空间或者其他资源一直处于Terminating状态,是由于资源调度到的节点处于NotReady状态,需要将节点重新加入到集群使其状态变为Ready状态才能解决问题,当node重新加入处于Ready状态后,…

系统报错msvcr120.dll丢失一键修复教程,快速修复dll报错问题

今天,我将和大家探讨一个常见的问题:系统报错msvcr120.dll丢失。这个问题相信很多网友都遇到过,尤其是在使用一些较老的软件或者游戏时,很容易出现这个错误。那么,如何解决这个问题呢?下面,我将…

Matlab(结构化程式和自定义函数)

目录 1.脚本编辑器 2.脚本流 2.1 控制流 2.2 关系(逻辑)操作符 3.脚本与函数 1.脚本编辑器 Matlab的命名规则: 常用功能: 智能缩进: 在写代码的时候,有的时候代码看起来并不是那么美观(可读性…

在线查询让家长迅速获得录取通知书

发布录取通知书是一项看似简单却非常耗时费力的工作。负责录取工作的老师通常会采取以下常见的发放方式: 1. 面试告知:某些学校会在面试结束后立即告知学生是否被录取。这种方式通常适用于面试人数较少的学校或特定专业。 2. 电子邮件:学校通…

pytorch中torch.gather()简单理解

1.作用 从输入张量中按照指定维度进行索引采集操作,返回值是一个新的张量,形状与 index 张量相同,根据指定的索引从输入张量中采集对应的元素。 2.问题 该函数的主要问题主要在dim维度上,dim0 表示沿着第一个维度(行…

P21~22 第六章 储能元件——电容存储电场能,电感存储磁场能

1、电容元件 a定义 b线性时不变电容元件 c电容的电压与电流关系 i有限则u有限 注意理解面积 d电容的功率和储能 e例一 跃变就是指物体的物理量从有限值变为无限值的过程。 分析上图例题:对于电源波形要吃负无穷到正无穷去刻画。即时间轴要铺满。 有有图控制电…

Mysql001:Mysql概述以及安装

前言:本课程将从头学习Mysql,以我的工作经验来说,sql语句真的太重要的,现在互联网所有的一切都是建立在数据上,因为互联网的兴起,现在的数据日月增多,每年都以翻倍的形式增长,对于数…

服务器数据库中了locked勒索病毒怎么办,locked勒索病毒恢复工具

最近一段时间网络上的locked勒索病毒非常嚣张,自从6月份以来,很多企业的计算机服务器数据库遭到了locked勒索病毒的攻击,起初locked勒索病毒攻击用友畅捷通T用户,后来七月份开始攻击金蝶云星空客户,导致企业的财务系统…