自定义类型:结构体进阶学习分享

【C语言总结篇】新起点 写了这么久的博客,来一个简单的自我介绍: 本人是上海师范大学的一名计科专业的大一新生,暑假时通过网上的各类资源也记录下了不少的文章,从高中开始就对编程有产生浓厚的兴趣,我知道在这方面想要有一定造诣前方定会艰难重重,但我对自己抱有足够的信心,我认为:有志者,事竟成。 我的编程目标: 学习好C/C++,Linux环境平台,计算机网络,数据库等……,希望能在大三的实习/校招时取得一份令我满意的offer。 我的学习思路: 1、在大一时学好C/C++,不仅仅是学完(学扎实,弄清楚); 大二学习STL、L 阅读详情

前言

结构体在C语言中具有重要的意义。它不仅可以封装和组织数据,还可以提供抽象和封装的能力,方便数据的传递和操作,提高代码的可读性和可维护性,是C语言中常用的数据类型之一。本篇博客将详细介绍相关知识。

1 结构体的基础知识

在结构体初阶我们以及详细介绍过了有关结构体的基础。

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

2 结构的声明

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

例如描述一个学生:

struct Stu
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
};

3 特殊声明

在声明结构体的时候,可以不完全声明。(匿名结构体声明)
比如:

//匿名结构体
struct
{
	int a;
	char b;
	float c;
}x;
struct
{
	int a;
	char b;
	float c;
}*px;

上面的两个结构在声明的时候省略掉了结构体标签(tag)。
那问题来了?

//在上面代码的基础上,下面的代码合法吗?
px = &x;

警告:

  • 编译器会将上面的两个声明当成完全不同的两个类型。所以是非法的。

4 结构的自引用

在结构中包含一个类型为该结构本身的成员是否可以呢?

struct Node//err,比如计算其大小sizeof(struct Node)时,大小是不确定的
{
	int date;
	struct Node next;
};

//正确的自引用方法
struct Node
{
	int date;
	struct Node* next ;
};

注意: 上面结构体类型有时过于冗杂,我们可以采用重命名。

//我们知道结构体可以匿名。那是否可以重命名呢?
//答案是否定的。
//例如下面这段代码,结构体中的Node* next变量还没有创建成功,结构体不是完整的,因此不可重命名
typedef struct//err
{
	int date;
	Node* next;
}Node;

//正确使用
typedef struct Node
{
	int date;
	struct Node* next;
}Node;

5 结构体变量的定义和初始化

有了结构体类型,那如何定义和初始化呢?其实很简单。

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

struct Point
{
	int x;
	int y;
};
struct Node
{
	int date;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5}, NULL };//结构体嵌套初始化

6 结构体内存对齐

接下来我们将介绍一个热门考点:结构体内存对齐
结构体内存对齐规则:

1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数与该成员大小的 较小值 。
。vs默认的值为8
。Linux中没有默认对齐数,对齐数就是成员自身的大小

3. 结构体的总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

6.1 计算结构体大小相关笔试题(基于VS)

笔试题一:

#include <stdio.h>

struct S1
{
	char c1;//对齐到偏移量为0处
	int i;//int占4个字节,VS默认对齐数为8;所以对齐数为最小值:4字节
		  //所以int对齐到偏移量为4后在向后移动4个字节即为。该位置即是int在内存中占据的空间
	char c2;//同理char的对齐数为1。在int后移动一个字节即可。
};
//上述结构体struct S1共占据9个字节,而结构体的大小必须是最大对齐数4(本题中,对齐数分别为1,4,1)的整数倍
//所以结构体还需向内存申请3个字节空间大小,及总大小为12字节。

struct S2
{
	char c1;//第一个变量成员对齐到偏移量为0处
	char c2; //该变量对齐数为1(char为1byte, VS默认为9byte,取最小值)
			 //即在变量c1后申请1字节即可
	int i;//该变量对齐数为4(int为4byte, VS默认为9byte,取最小值)
		  //所以变量i对齐到偏移量为4处,在向后申请4个字节即可。
};
 //到此结构体总共向内存申请了8byte, 为最大对齐数4(本题中三个变量对齐数分别为:1,1,4)的整数倍。
 //所以该结构体的最终大小为8
 
int main()
{
	printf("%d\n", sizeof(struct S1));
	printf("%d\n", sizeof(struct S2));
	return 0;
}

运行结果:
在这里插入图片描述
—————————————————————————————————————

笔试题二:

struct S3
{
	double d;//第一个成员变量对齐到偏移量为0处,在向后申请8字节(double大小为8)
	char c;//该成员变量对齐数为1(char为1byte,VS默认对齐数为8,取最小值)
		   //所以变量对齐到偏移量为8处,向后申请1byte
	int i;//该成员变量对齐数为4(int为4byte,VS默认对齐数为8,取最小值)
		  //所以该变量首先要对齐到偏移量为12的位置(必须对齐到4的整数倍处),在向后申请4个字节
};
//到此该结构体向内存共申请了16字节,为最大对齐数8的整数倍
//所以该结构体的最终大小为16byte

struct S4
{
	char c1;//第一个成员变量对齐到偏移量为0处,在向后申请1字节(char大小为1)
	struct S3 s3;//嵌套结构体,结构体要对齐到自己最大对齐数8(上面已经求得最大对齐数为:8)的整数倍处。即该成员变量对齐到偏移量为8出,在向后申请16字节(上面已经求出其大小16byte)
	double d;//该成员变量对齐数为8(double为8byte,VS默认对齐数为8,取最小值)
		     //上述两个变量总共为24个字节,所以该成员变量从偏移量为24(刚好为8得整数倍)开始,在向后申请8字节
};
//到此该结构体总共占据32个字节空间,为最大对齐数8(上述3个成员变量对齐数分别为:1,8,8)的整数倍。
//所以最终该结构体总大小为32byte

int main()
{
	printf("%d\n", sizeof(struct S3));
	printf("%d\n", sizeof(struct S4));
	return 0;
}

运行结果:
在这里插入图片描述

6.2 为什么存在内存对齐?

大部分参考资料是这么说的:

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

总的来说:

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

6.3 如何设计结构体减少空间

在设计结构体时,我们既要满足对齐,又要节省空间,如何做到呢?

我们前面已经见过这段代码:

struct S1
{
	char c1;
	int i;
	char c2;
};
struct S2
{
	char c1;
	char c2; 
	int i;
}
int main()
{
	printf("%d\n", sizeof(struct S3));//12
	printf("%d\n", sizeof(struct S4));//8
	return 0;
}

S1和S2类型的成员一模一样,但是S1和S2所占据的空间大小有一些区别。我们可以得到:

  • 在设计结构体时,尽量让占用空间小的成员尽量集中在一起,从而节省空间。

1.7 修改默然对齐数

#pragma这个预处理指令可以被用来修改我们的默认对齐数。

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

运行结果:
在这里插入图片描述
总结:

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

8. 结构体传参

直接上代码:

#include <stdio.h>
struct S
{
	int date[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* s)
{
	printf("%d\n", s->num);
}

int main()
{
	print1(s);
	print2(&s);
	return 0;
}

上面print1和print2函数那个更好?
答案是:首选print2函数。
原因:

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

结论:

结构体传参时,要传结构体指针。

9. 结尾

本篇博客到此就结束了。传作不易,如果对你有帮助记得三连哦!感谢您的支持!!!

手把手教你用VS Code + Codex在WSL中高效编程(避坑指南) 本文提供了一份详细的避坑指南,教你如何在WSL环境中高效配置和使用VS Code与OpenAI Codex。文章核心在于解决WSL内Codex扩展的OAuth登录失败问题,推荐将扩展安装在Windows本地,并通过UNC路径直接访问WSL文件系统,从而实现AI辅助编程与Linux开发环境的无缝结合,提升编码效率。 阅读详情

相关推荐

Linux USB Gadget框架解析:从设备模拟到驱动开发实战

USB(通用串行总线)是现代计算机系统中应用最广泛的外设连接标准,其主从动态切换的特性使其在嵌入式系统中扮演着双重角色。与I2C、SPI等固定主从架构不同,USB设备需要同时支持主机(Host)和从机(Device)两种模式,这催生了Linux内核中独特的USB Gadget框架。该框架通过分层设计,将硬件控制器驱动(UDC)、功能逻辑(Function)和配置管理(Configfs)解耦,实现了灵活的设备模拟能力。在工程实践中,开发者可以利用Gadget框架快速实现U盘、网络适配器、串口转换器等常见USB

weixin_28007513的博客 560

自定义类型-结构体详解

深度讲解结构体定义,初始化,函数传参,枚举,联合体等自定义类型应用

k666499436的博客 1万+

Habitat-baselines v0.1.7防踩坑手把手带你跑通(全网唯一)

Habitat-baselines v0.1.7防踩坑手把手带你跑通(全网唯一)

shannanshouyin的博客 1275

【自定义类型】结构体,联合,枚举

在我们学习C语言的时候,有几个自定义类型需要我们掌握,那么我也是根据自己的学习来分享一下自己的理解。希望与大家互相学习,共同进步! 文章目录一:结构体1.1:结构体的基础知识1.2:结构的声明1.3:特殊的声明1.4:结构体的自引用1.5:结构体变量的定义和初始化1.6: 结构体内存对齐1.7:修改默认对齐数1.8:结构体传参二:位段2.1:什么是位段2.2:位段的内存分配2.3:位段的跨平台问题三:枚举3.1:枚举类型的定义3.2:枚举的优点3.3:枚举的使用四:联合(共用体)4.1联合类型的定义4.2

qq_43727529的博客 1330

基于深度学习实现实时视频目标检测

实时视频目标检测是计算机视觉领域的研究热点之一,其应用场景包括智能监控、自动驾驶、机器人视觉等多个领域。深度学习技术的快速发展使得实时视频目标检测变得更加可行和准确。本文提出一种基于深度学习实现的实时视频目标检测系统,使用Python和OpenCV作为开发工具,具有高效、准确和实时的特点。 本系统的主要需求是实现实时视频目标检测功能,可以在不同的应用场景中使用。具体的需求如下:2.1 视频输入本系统需要从摄像头或视频文件中获取实时视频流,并对视频流中的目标进行检测和跟踪。2.2 目标检测本系统需要使用深度学

分享毕业设计的案例和论文 1940

别再折腾CUDA了!Win11上VSCode一键配置PyTorch GPU环境(附Anaconda虚拟环境避坑指南)

本文提供Win11系统下使用VSCode和Anaconda一键配置PyTorch GPU环境的详细指南,解决CUDA版本冲突等常见问题。通过conda的原子化依赖解决方案,安装时间从2小时缩短至15分钟,适合深度学习初学者快速搭建开发环境。

weixin_33101399的博客 246

C语言自定义类型:结构体

本文详细讲解了结构体的创建和结构体的内存对齐,还涉及了结构体的传参和结构体实现位段,轻松易懂,小白可入.

wer24_25的博客 1469

BOE CHPI协议解析:高速显示驱动的核心技术

本文深入解析了BOE CHPI协议,这是一种为高分辨率、高刷新率显示面板设计的时钟嵌入式高速点对点接口技术。文章详细阐述了其三层架构(物理层、链路层、协议层)、核心机制(如链路训练与BCC通道)以及如何通过高速串行差分传输解决大尺寸屏幕内部数据传输的带宽与干扰难题,是驱动8K、窄边框等高端显示应用的关键核心技术。

m9n0o的博客 543

【C语言进阶(七)】自定义类型--结构体,位段,联合

结构体内存对齐规则详细介绍,位段,联合体详细讲解,内附代码和图文讲解,看完就能学会!

杭电码农-NEO的博客 843

电子数据取证实战:从“平航杯”竞赛看计算机检材分析的关键技术与案例解析

本文通过'平航杯'电子数据取证竞赛案例,深入解析计算机检材分析的关键技术,包括USB设备追踪、浏览器历史分析、AI换脸取证、虚拟货币交易追踪等实战技巧。重点探讨了数字痕迹的发现与关联,以及电子取证工具链的应用,为从业人员提供实用的技术参考和案例分析。

www00的博客 533

开源免费!ReaLTaiizor如何用MIT许可证打造专业级WinForm UI?

摘要: ReaLTaiizor是一款开源UI控件库,为WinForm应用提供现代化界面解决方案。支持100+组件、多主题切换(浅色/深色/自定义)和.NET 4.8-8.0全版本兼容,MIT许可证允许免费商用。通过NuGet快速安装,3步改造传统界面:1)注入主题(如this.Theme = new Dark()),2)替换原生控件为高颜值组件(如ModernGrid替代DataGridView),3)集成高级功能(分页/动画提示)。典型场景包括登录界面美化(进度动画+通知控件)和数据表格Material风

墨夶的博客 1520

C语言进阶——chapter4——自定义类型之结构体

好了,今天的分享就到这里了在学习C语言的道路上Humble与各位同行,加油吧各位!让我们在接下来的时间里一起成长,一起进步吧!

2301_79345909的博客 265

TC397 EB MCAL开发从0开始系列 之 [13.1] Dma配置实战 -实现M2M数据传输(读存储写存储)

TC3XX TC397 MCAL DMA 从0搭建测试用例-实现M2M 存储到存储数据传输

yy九歌的博客 1912

【C语言】——自定义类型详解:结构体,枚举,联合

【C语言】自定义类型详解

m0_71214261的博客 491

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

[C语言]自定义类型(结构体~枚举~联合体)

这里有对结构体,位段,枚举,共用体有细致的讲解,快进来学习吧。

分享技术 381

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

匿名结构体类型、结构体的自引用、结构体的内存对齐以及结构体传参

在C语言中有着各种数据类型,这些类型有配划分为内置类型和自定义类型两大类(如下图)。铁子们,今天阿辉要分享的就是自定义类型中的结构体联合体和枚举将在下篇文章分享,至于数组阿辉之前的文章数组篇中已经详细讲到,铁子们感兴趣的话可以点击跳转😘,不多bb直接开始我们今天的学习👊。

m0_75108739的博客 1898

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C语言学习系列—>一篇带你了解结构体

结构体是C语言中自定义类型之一,当内置类型不能满足的时候,我们就可以使用自定义类型,在后续数据结构的学习过程中会遇到很多关于结构体的内容,所以,小编将在学习结构体时的笔记分享一番。结构体是一个集合,里面的成员变量可以是不同类型的。

Giggins GaoBlog 853

自定义类型:结构体

在上面的博客中展示的代码中就有结构体成员的访问操作符,就是一个.,这个就被称为结构体的成员访问符号。大家请看下面的代码图片。其实还有另外一种初始化的方式,叫做按指定顺序的初始化,接下来,我就来给大家展示一下按指定位置初始化的方法,大家请看下面的图片。好了,这就是我今天想要分享的有关结构体的博客,以上的代码感兴趣的朋友可以照着感觉在自己的编译器上尝试尝试。看了上面的结构体的创建,接下来,我就来给大家好好讲一讲结构体的初始化以及结构体的成员访问,大家请看下面的代码图片,这张图片我将给大家展示结构体的初始化。

DREW_Smile的博客 372

C语言 自定义类型:结构体

分享了C语言中结构体的简单创建

bigen_er的博客 337

【c语言进阶】结构体最常用知识点大全

结构体最常用知识点大全

睿的博客 1059

【C语言】自定义类型:结构体(内存对齐),2024年最新大厂面试必问

有了结构体那么如何定义变量,int data;int x;int y;}p1;//声明类型的同时定义变量p1//定义结构体变量p2//初始化:定义变量的同时赋值位段的成员必须是位段的成员后边有一个冒号和一个数字struct A {int a : 2;int b : 5;int c : 10;int d : 30;位段中的位其实是二进制位,后面的2就是表示2个比特位,后面也是如此。

2401_84181340的博客 695

掌握C语言自定义类型:结构体、共用体与枚举应用

在实际使用中,我特别注意到了结构体初始化的顺序要求,以及通过成员运算符(.和->)访问成员变量的方式差异。这些特性的学习让我认识到,C语言虽然接近底层,但通过结构体等复合数据类型,仍然可以构建出高度抽象的数据模型。结构体与qsort函数的配合使用让我印象深刻。提供给用户可以自定义一种数据类型 --- 程序员根据问题的需要,自己组织的数据类型,可以描述现实生活中一些基本数据类型不好描述的场景,结构体可以把不同类型的数据集合在一起。所谓"枚举"是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。

kkkkkingw的博客 332

结构体的介绍

为什么要有结构?在我学习C语言以来,在创建变量时它们的类型无非就是整型,浮点型,字符型,如果我们用来描述一个复杂的物或者人,难免有些麻烦,在这个的情况下我学习到了自定义类型:结构体,发现它真的有时候很是方便,在这我就来分享一下自己对结构体的认识,如果有什么错误,欢迎指正。!在调用或者声明时,我们得定义一下。int number;首先struct是结构体的关键字,其后的Tag是标签这可以随便的取名(只要你觉得有价值就行)标签和。

w843803110302005的博客 1058

C语言进阶第七课-----------自定义类型的讲解(结构体枚举联合)

*作者前言**结构体结构体的声明结构的基础知识声明结构的自引用结构体变量的定义和初始化结构体内存对齐结构体内存对齐的意义修改默认对齐数结构体传参位段位段的内存分配位段跨平台的问题枚举枚举的定义枚举的优点联合体联合体的定义联合体大小的计算联合体的应用总结在前面我写的结构体声明有很多种,初始化也有多种int a;int b;//5。

m0_69984273的博客 3034

【C语言】自定义类型之 --- 结构体(重要~)

C语言中结构体是一种用户自定义的数据类型,它相当于一个小型的数据结构,当我们在学数据结构阶段的时候,结构体的运用很常见。所以,基本的结构体的定义和使用,以及结构体大小的计算务必掌握。结构体的知识虽然较为简单,但其在数据结构当中的作用还是很重要的,因为一个数据它里面要有什么内容还是要结构体来整合。

Welcome home | Jian Liao 's blog 1007

自定义类型:结构体、枚举、联合体(C语言系列19)

C语言中的自定义有哪些,你知道吗?

weixin_61599986的博客 831
上一篇: 指针进阶详解(下)
下一篇: 字符函数和字符串函数解析及模拟实现
小白debug~
小白debug~ 新星创作者: C/C++技术领域 新星创作者: C/C++技术领域
博客等级 码龄4年 3510粉丝 128原创
评论 56
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白debug~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值