C语言自定义类型讲解:结构体,枚举,联合(1)

news2024/12/24 2:21:17

🐵本篇文章将对结构体相关知识进行讲解

1.结构体🖥️

1.1结构体定义

结构体(struct)是用户自定义的数据类型,用于组合一个或多个不同类型的数据成员

1.2结构体的声明

这里直接以代码为例

1.3特殊的声明

不完全声明或者说匿名声明

在这种情况下,该结构体类型只能使用一次,在创建该结构体类型变量时只能如上图所示创建,以下几种情况均错误:

//1
struct
{
	int age;
	float score;
} a;

int main()
{
	struct b;
	printf("%d", b.age); //报错,因为struct类型已经在上面创建a变量时使用过一次
	return 0;
}

//2
struct
{
	int age;
	float score;
};
int main()
{
	struct b;
	printf("%d", b.age);//由于是匿名结构体,编译器无法识别struct类型
	return 0;
}

那如果这样写代码:

struct
{
	int age;
	float score;
} b;

struct
{
	int age;
	float score;
}* p;

int main()
{
	p = &b;
	return 0;
}

该代码定义了两个匿名结构体类型的变量,且两个结构体的内部成员相同,现将结构体变量b的地址赋给结构体指针p发现,编译器会报警告

也就是说编译器会将这两个结构体类型视为不同的类型,所以不建议这样写代码

在一般情况下不会使用匿名结构体,如果该结构体只使用一次可以用匿名结构体

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

struct Student
{
	char name;
	int age;
}s1;  //在声明的同时定义变量,此时为全局变量

struct Student s2; //全局变量
int main()
{
	struct Student s3 = { "sans",3}; //局部变量
	return 0;
}

嵌套结构体的初始化和访问

struct Point
{
	int x;
	int y;
};

struct Node
{
	int data;
	struct Point p;
	struct Node* next;
};

int main()
{
	struct Node s3 = { 23, {2,3}, NULL };
	printf("%d %d %d", s3.data, s3.p.x, s3.p.y);//先访问到结构体Point在访问其内部成员
	return 0;
}

1.5结构体的内存对齐

1.5.1结构体大小的计算

接下来讲解如何计算结构体的大小,对于计算结构体的大小并非只是将其内部成员的大小加起来,而是通过结构体对齐规则来计算的:

  • 1. 第一个变量在与结构体变量偏移量为0的地址(初始地址)处

这里介绍一个宏:offsetof:用来计算结构体成员相较于起始地址偏移量的

struct S1
{
	char c1;
	int i;
	char c2;
};
int main()
{
    printf("%d", offsetof(struct S1, c1));//结果为0
    return 0;
}
  • 2. 其他成员变量要对齐到对齐数的整数倍的地址处
    对齐数 = 编译器默认的一个对齐数与该成员大小的较小值
    vs的对齐数默认为8
  • 3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
  • 4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己内部成员的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
     

下面通过例题进行讲解:

struct S1
{
	char c1;
	int i;
	char c2;
};
printf("%d\n", sizeof(struct S1));

首先c1是第一个成员,要将它放在结构体变量偏移量为0的地址处,下来i为整形,i的大小为4个字节,vs的默认对齐数是8,所以i的对齐数是8和4的较小值也就是4,要将i对齐到4的整数倍的地址处,就是下面偏移量为4的地址处,再下面是c2,c2的对齐数是1,要将c2对齐到1的整数倍的地址处,就是下面偏移量为8的地址处,此时整个结构体的大小为9个字节,规定结构体的总大小是最大对齐数的整数倍,该结构体的最大对齐数是4,所以应该是12个字节                         


struct S2
{
	char c1;
	char c2;
	int i;
};
printf("%d\n", sizeof(struct S2));

c1是第一个成员,将它放在结构体变量偏移量为0的地址处,c2的对齐数是1,将它对齐到1的整数倍的地址处,i的对齐数是4,将他对齐到4的整数倍的地址处,此时整个结构体的大小是8个字节,正好也是成员最大对齐数4的整数倍,所以这个结构体的大小就是8给字节


struct S3
{
	double d;
	char c;
	int i;
};
printf("%d\n", sizeof(struct S3));

d是第一个成员,将它放在结构体变量偏移量为0的地址处,c的对齐数是1,将它对齐到1的整数倍的地址处,i的对齐数为4,将它放在4的整数倍的地址处此时整个结构体的大小为16个字节,同时也是成员最大对齐数8的整数倍,所以结构体的大小就是16个字节


struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
printf("%d\n", sizeof(struct S4));

c1是第一个成员,要放在结构体变量偏移量为0的地址处,下来是一个嵌套的结构体,规则约定嵌套结构体要对齐到自己内部成员最大对齐数的整数倍处,其内部成员的最大对齐数是8,所以要对齐到8的整数倍的地址处,d的对齐数是8,要对齐到4的整数倍的地址处,此时结构体的大小为32个字节,正好是最大对齐数16的整数倍,所以结构体的大小就是32个字节

1.5.2结构体内存对齐的原因

1. 平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特
定类型的数据。

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

struct S1
{
	char c;
	int i;
};

上述代码中在没有对齐的情况下:

在对齐的情况下:

因此结构体的内存对齐可以理解为用空间换取时间的做法

但如果既要满足对齐又想节省时间,可以尽量将小的变量放在一起


1.5.3修改默认对齐数

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

#include<stdio.h>

#pragma pack(1) //将默认对齐数修改为1
struct S1
{
	char c1;
	int i;
	char c2;
};
#pragma pack() //修改后记得取消默认对齐数

struct S2
{
	char c1;
	int i;
	char c2;
};

int main()
{
	printf("%zd\n", sizeof(struct S1)); //6
	printf("%zd\n", sizeof(struct S2)); //12

	return 0;
}

1.6结构体传参

#include<stdio.h>

struct S
{
	int data[100];
	int num;
};

void print(struct S t)
{
	printf("%d %d %d %d", t.data[0], t.data[1], t.data[2], t.num);
}

int main()
{
	struct S s = { {1,2,3}, 10 };
	print(s); //传值调用

	return 0;
}

在函数调用时,形参是实参的一份临时拷贝,当我们传过去的结构体过于大时,形参也需要申请同样大的空间,除此之外还需要将结构体的数据一个一个传过去,既浪费时间也浪费空间,所以对结构体传参时通常会采用传址调用

#include<stdio.h>

struct S
{
	int data[100];
	int num;
};

void print(struct S* t)
{
	printf("%d %d %d %d", t->data[0], t->data[1], t->data[2], t->num);
}

int main()
{
	struct S s = { {1,2,3}, 10 };
	print(&s); //传址调用

	return 0;
}

🙉本篇对结构体的讲解结束,下一篇会对位段、枚举以及联合等相关知识进行讲解

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

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

相关文章

Windows 基于Visual Studio 开发Qt 6 注意事项

前提条件&#xff1a; 1、Visual Studio 2022 社区版(免费版) 2、Qt-6.5.1版本 Qt Vistual Studio Tools下载 先打开Visual Studio 2022 社区版 &#xff1a; 点击扩展-》管理拓展按钮后&#xff0c;在搜索框中输入Qt&#xff0c;点击这里第一个扩展安装。 Qt Visual Stud…

Matlab信号处理:FFT频谱分辨率

频谱分辨率&#xff1a; 其中为采样间隔&#xff0c;为采样点数。 FFT分辨率&#xff1a; 其中为采样频率&#xff0c;为FFT点数。 有两正弦函数&#xff0c;频率分别为 f1 1Hz&#xff0c;f2 10Hz&#xff0c;f3 40Hz&#xff1b; 示例1&#xff1a; 采样频率 fs 1000H…

LwIP笔记02:

一、LwIP源文件 api&#xff1a;NETCONN API 和 Socket API 相关的源文件&#xff0c;在有操作系统环境下使用 apps&#xff1a;应用程序源文件&#xff0c;如http、mqtt、tftp等 core&#xff1a;LwIP内核源文件 include&#xff1a;LwIP所有模块对应的头文件 netif&…

基于AlgoT1设备改进多源融合定位算法(GNSS+INS+VISION)

AlgoT1是融合了GNSSIMUVISION的数据平台&#xff0c;用该设备实测了一组数据&#xff0c;并且在开源代码上进行了改进&#xff0c;得到的效果还行&#xff0c;对做多源融合算法研究是个不错的选择。 0.设备图 这款设备是上海代数律动技术有限公司新出的机器(http://www.algot…

2023 年 Android 毕业设计选题推荐,200 道 Android 毕业设计题目,避免踩坑

前言 选择一个Android毕业设计题目是一个重要的决策&#xff0c;它将影响你未来几个月的工作。以下是一些关于如何选择一个合适的Android毕业设计题目以及如何避免踩坑的建议&#xff1a; 兴趣和热情&#xff1a;首先&#xff0c;选择你真正感兴趣的领域。如果你对某个领域充…

【算法思想】排序

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

Spring面试题12:Spring中IOC的优缺点是什么?IOC依赖注入方式有哪些

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring中IOC的优缺点是什么? IOC(Inversion of Control,控制反转)是Spring框架的一个重要特性,它实现了对象的创建和依赖关系的管理的反转。…

Activiti7工作流 一【工作流介绍、什么是Activiti7?、Activiti7环境、集成Activiti7、流程引擎API】

文章目录 Activiti7工作流一、工作流介绍1.1 概念1.2 适用行业1.3 应用领域1.4 传统实现方式1.5 什么是工作流引擎 二、什么是Activiti7&#xff1f;2.1 概述2.2 Activiti7内部核心机制2.3 BPMN2.4 Activiti如何使用2.4.1 整合Activiti2.4.2 业务流程建模2.4.3 部署业务流程2.4…

小说界的卷王巴尔扎克,咖啡续命拼命搞钱

巴尔扎克每天工作18小时&#xff0c;咖啡续命&#xff0c;活活累死。 巴尔扎克高产似母猪&#xff0c;写了90多部小说。 巴尔扎克很肤浅&#xff0c;除了写小说&#xff0c;就是搞钱&#xff0c;却一直是贫穷的状态。 一、卷王 1799年&#xff0c;奥诺雷德巴尔扎克出生在法国…

怎么快速提取图片中的文字信息?怎么使用OCR图片文字提取一键提取文字

图片里的文字如何提取?一些图片中的文字信息是我们需要的&#xff0c;但是一个个输入太麻烦了&#xff0c;怎么将图片上的文字提取出来?Initiator是一款易于使用的小型 macOS OCR&#xff08;光学字符识别&#xff09;应用程序&#xff0c;可提取和识别 Mac 计算机屏幕上的任…

自监督学习之对比学习:MoCo模型超级详解解读+总结

文章目录 一、MoCo简介1.1 整体思想1.2 动量1.3 正负样本如何选取 二、动态字典2.1 query和key2.2 字典特点 三、编码器的动量更新3.1 编码器的更新规则3.2 使用动量更新的原因 四、实验过程4.1 目标函数&#xff1a;infoNCE4.1.1 softmax4.1.2 交叉熵损失4.1.3 交叉熵损失函数…

【蓝桥杯选拔赛真题62】Scratch判断小球 少儿编程scratch图形化编程 蓝桥杯选拔赛真题解析

目录 scratch判断小球 一、题目要求 编程实现 二、案例分析 1、角色分析

BottomNavigationView3个以上图标不显示文字

问题 当BottomNavigationView设置的菜单中超过三个图标时&#xff0c;出现只有焦点聚集到图标时才会显示底部设置的文字描述&#xff0c;当没有焦点聚集则只显示图标&#xff0c;效果如下&#xff1a; 解决办法 设置labelVisibilityMode值 如果BottomNavigationItemView类并…

Jmeter——结合Allure展示测试报告

在平时用jmeter做测试时&#xff0c;生成报告的模板&#xff0c;不是特别好。大家应该也知道allure报告&#xff0c;页面美观。 先来看效果图&#xff0c;报告首页&#xff0c;如下所示&#xff1a; 报告详情信息&#xff0c;如下所示&#xff1a; 运行run.py文件&#xff0c;…

Java笔记:认识一下class文件

1.class文件概述 我们可任意打开一个Class文件&#xff08;使用Hex Editor等工具打开&#xff09;&#xff0c;内容如下&#xff08;内容是16进制&#xff09;&#xff1a; 十六进制转字符串&#xff1a;http://www.bejson.com/convert/ox2str/ 进制转换网址&#xff08;十六进…

谷歌浏览器jsonView插件安装与使用

1、打开 https://github.com &#xff1b; 2、搜索 jsonView 链接&#xff1a;https://gitee.com/wangl2020/chrome_JSONVue 3、选择需要的插件我是选这个&#xff1b; 4、点击【Download Zip】&#xff0c;插件下载完成&#xff0c;解压缩到相应目录&#xff08;D:\Downloa…

外贸电商独立站的选品和运营

第一步&#xff1a;选品 做出口跨境电商卖家&#xff0c;最难回答的问题就是我要卖什么产品&#xff1f;销量好的产品&#xff0c;竞争太激烈&#xff1b;价格很高的又卖不动&#xff1b;太小众的又担心客户不好开发&#xff0c;很纠结&#xff01; 的确&#xff0c;对于出口B2…

若依cloud -【 100 ~ 103 】

100 分布式日志介绍 | RuoYi 分布式日志就相当于把日志存储在不同的设备上面。比如若依项目中有ruoyi-modules-file、ruoyi-modules-gen、ruoyi-modules-job、ruoyi-modules-system四个应用&#xff0c;每个应用都部署在单独的一台机器里边&#xff0c;应用对应的日志的也单独存…

数据结构-----堆(完全二叉树)

目录 前言 一.堆 1.堆的概念 2.堆的存储方式 二.堆的操作方法 1.堆的结构体表示 2.数字交换接口函数 3.向上调整&#xff08;难点&#xff09; 4.向下调整&#xff08;难点&#xff09; 5.创建堆 6.堆的插入 7.判断空 8.堆的删除 9.获取堆的根(顶)元素 10.堆的遍历…

Linux中sudo命令的添加和操作

使用 sudo分配权限 &#xff08;1&#xff09;修改/etc/sudoers 文件分配文件 # chmod 740 /etc/sudoers # vi /etc/sudoers 找到这行&#xff1a;root ALL(ALL) ALL, 在这行下面添加 xxx ALL(ALL) ALL (这里的xxx就是你的普通用户&#xff0c;而ruice就是我的普通用户 ) 编…