[C语言]结构体、位段、枚举常量、联合体

目录

结构体

结构体的使用方法

结构体所占用的大小

位段

位段的使用方法

位段所占用的大小

枚举常量

枚举常量的使用方法

枚举常量的优势

联合体

联合体的使用方法

结构体

结构体的使用方法

结构体是一些值的集合,我们可以定义一个结构体,里面可以包含不同类型的值例如定义一个学生我们可以这样使用结构体

那我们要输入一个学生的信息应该如何呢?

我们写一段这样的代码

#include <stdio.h>
struct stu
{
	char name[20];//名字
	int age;//年龄
	char sex[5];//性别
	char id[20];//学号
}s2 = { "Hardworker2",28,"女","20240323002" };
void main()
{
	struct stu s1 = { "Hardworker1",18,"男","20240323001" };
	printf("%s %d %s %s\n", s1.name, s1.age, s1.sex, s1.id);
	printf("%s %d %s %s\n", s2.name, s2.age, s2.sex, s2.id);
}

这段代码的运行结果如下

可以看到在结构体后面跟一个变量也可以完成结构体的初始化,或者在主函数再次声明变量也可也初始化,这两种有什么区别呢?区别就是在结构体后初始化的变量如果在主函数之上就是一个全局变量,而在主函数内的变量为局部变量。

另外结构体声明也可以调用结构体,如

struct Point
{
	int x;
	int y;
}p1;
struct Point p2;
//声明类型的同时定义变量p1
 //定义结构体变量p2
 //初始化:定义变量的同时赋初值。
struct Point p3 = { x, y };
struct Stu
{
	//类型声明C
	char name[15];//名字
	int age;
	//年龄
};
struct Stu s = { "zhangsan", 20 };//初始化
struct Node
{
	int data;
	struct Point p;
	struct Node* next;
}n1 = { 10, {4,5}, NULL };
//结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化

在结构体内调用其他的结构体也是可以的,那我们能不能在结构体内部调用自己呢?

用这种方式是不行的,因为如果再次调用自己的话,就会再次开辟一次内存,内存会一直递归开辟,直到程序崩溃,但是我们可以用指针的方式调用自己,需要注意的是,我们需要的是一部分装我们想要的数据,另外一部分装下一个需要相同类型结构体的地址,如下

为了方便理解,笔者写了一段代码便于理解如何一部分装值一部分装地址

#include <stdio.h>

struct Node
{
	int value;
	struct Node* next;
};

void print_chain(struct Node* init)
{
	while (init->next)
	{
		printf("%d", init->value);
		init = init->next;
		if (!(init->next))
		{
			printf("%d", init->value);
		}
	}
}
void main()
{
	struct Node f = { 1,NULL };
	struct Node e = { 2,&f };
	struct Node d = { 3,&e };
	struct Node c = { 4,&d };
	struct Node b = { 5,&c };
	struct Node a = { 6,&b };
	print_chain(&a);
}

我们看到依次打印为654321

结构体所占用的大小

如下程序,结构体占用的大小是多少呢

按理来说char占用一个字节int占用四个字节那么一共就是六个字节,但是当我们输出sizeof(S1)却发现结果为12个字节,那结构体在内存中是怎么进行存放的呢?

我们来看一下结构体给与内存的规则是怎么样的

1. 第一个成员在与结构体变量偏移量为0的地址处。

2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。 对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。 VS中默认的值为8

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

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

因此第一个char地址为偏移量为0的地方即为0

int类型的地址为某个数字(对齐数)的整数倍的地址处,编译器默认的一个对齐数 与 该成员大小的较小值 既为4的整数倍,因此1、2、3都不可以为int的地址,只有4存放,而int占4个字节大小,所以4-7均为int的地址

下一个char按照第二个规则继续存放,既存放到8的地址,而为什么没有结束呢?

按照3的规矩,总大小为最大对齐数的整数倍,所以我们必须再开辟三个字节让结构体的大小为12才可以结束,我们可以看看图片更为直观的理解结构体的大小占用

位段

位段的使用方法

位段的声明和结构是类似的,有两个不同:

1.位段的成员必须是 char int、unsigned int 或signed int 。

2.位段的成员名后边有一个冒号和一个数字。

如下

其实后面的冒号数代表的就是分配给其所占的比特数大小,那么位段的大小为多少呢?

位段所占用的大小

对于上面的位段我们来测试一下此位段所占用的大小

我们发现占用的大小为4个字节,但是按理来说,如果是比特数大小其字节数应该6<(2+16+32)/8<7 那为什么输出的结果为8呢?其实原因在于,对于一个整型变量,如果超出了四个字节之后,位段结构体会为其再开辟四个字节,但是问题又来了,c中存放的32个比特的数据是在后四个字节里面还是一部分再前四个字节里面一部分在后四个字节里面呢?

让我们给这三个参数赋值来看看答案如何

#include <stdio.h>

struct test 
{
	int a : 2;
	int b : 16;
	int c : 32;
}s;

void main()
{
	struct test d = { 1,30,20 };
	printf("%d", sizeof(s));
}

我们调用d的内存发现其存放的方式如下

其实我们仔细分析一下,a作为占2比特的变量,结构体分给其第一个字节后两位,接着剩下的还是在第一个定义的int的四个字节内,所以依次剩下的6个比特以及12个比特分给了b,如所示区域,但是当分配给c的时候,c占用32个比特,第一个int所占的四个字节无法接纳那么大的内存,所以开辟了一段新的空间给它,但是上一个没用完的空间是不分配给c的,所以我们最终看到系统分配内存方式如下

枚举常量

枚举常量的使用方法

枚举顾名思义就是一一列举。 把可能的取值一一列举。

比如我们现实生活中: 一周的星期一到星期日是有限的7天,可以一一列举。

性别有:男、女、保密,也可以一一列举。

月份有12个月,也可以一一列举

这里就可以使用枚举了。

枚举的代码如下所示

enum Day//星期
{
 Mon,
 Tues,
 Wed,
 Thur,
 Fri,
 Sat,
 Sun
};
enum Sex//性别
{
 MALE,
 FEMALE,
 SECRET
};
enum Color//颜色
{
 RED,
 GREEN,
 BLUE
};

上面所定义的量都称之为枚举常量,是不可以进行修改的常量。

拿颜色举例,就是赋值了

RED大小为0的枚举常量

GREEN大小为1的枚举常量

BLUE大小为2的枚举常量依次累加

如果想要定义RED为4

直接在enum的时候赋值RED=4就好

但是接下来的数据也会变成

GREEN = 5 ;BLUE =6

枚举常量的优势

枚举的优点:

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

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

3. 防止了命名污染(封装)

4. 便于调试

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

联合体

联合体的使用方法

联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体)。 比如:

#include <stdio.h
//联合类型的声明
union Un
{
 char c;
 int i;
};
//联合变量的定义
union Un un;
void main()
{
//计算连个变量的大小
 printf("%d\n", sizeof(un));
}

联合体,顾名思义就是里面定义的内容共用同一块内存区域,联合的大小至少是最大成员的大小。 当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

当每次赋值的时候,联合体内的内存都会被重新赋值

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

实例:NX二次开发使用链表进行拉伸功能(链表相关功能练习)

一、概述 在进行批量操作时经常会利用链表进行存放相应特征的TAG值&#xff0c;以便后续操作&#xff0c;最常见的就是拉伸功能。这里我们以拉伸功能为例子进行说明。 二、常用链表相关函数 UF_MODL_create_list 创建一个链表&#xff0c;并返回链表的头指针。…

STM32---DHT11温湿度传感器与BH1750FVI光照传感器(HAL库、含源码)

写在前面&#xff1a;本节我们学习使用两个常见的传感器模块&#xff0c;分别为DHT11温湿度传感器以及BH1750FVI光照传感器,这两种传感器在对于环境监测中具有十分重要的作用&#xff0c;因为其使用简单方便&#xff0c;所以经常被用于STM32的项目之中。今天将使用分享给大家&a…

Digital WooCommerce Stores: 创建数字WordPress商店的详细教程- US Domain Center主机

第一步&#xff1a;了解数字 WooCommerce 商店 数字 WooCommerce 商店是一种电子商务模式&#xff0c;其中您可以销售虚拟产品&#xff0c;如在线课程、电子书、PDF、图像和视频。您可以使用 WooCommerce 插件在您的 WordPress 网站上设置数字产品&#xff0c;并通过在线交易提…

pandas的综合练习

事先说明&#xff1a; 由于每次都要导入库和处理中文乱码问题&#xff0c;我都是在最前面先写好&#xff0c;后面的代码就不在写了。要是copy到自己本地的话&#xff0c;就要把下面的代码也copy下。 # 准备工作import pandas as pd import numpy as np from matplotlib impor…

查立得php+mysql源码通用数据库配置教程

适用范围&#xff1a; 查分吧PHP多条件都输对版已有表万用查询系统 phpMySql已有数据表通用搜索可增删改查 查立得快搜系统(phpMysql) v20220208 查立得万能查&#xff08;phpmysql&#xff09; v20220512 及 各付费版 等几十款源码 数据库配置路径 数…

ReNamer Pro+Alist+RaiDrive妙用:实现批量修改网盘文件名称

ReNamer ProAlistRaiDrive妙用&#xff1a;批量修改管理网盘文件 说明工具下载Alist和RaiDrive安装和使用Renamer Pro激活和使用 说明 批量修改网盘文件名称的软件也大量存在&#xff0c;但是要么收费要么不好用&#xff0c;alist中也存在使用lamda表达式修改文件名称&#xf…

GT20L16S1Y标准汉字字库芯片完全解析(2)

接前一篇文章&#xff1a;GT20L16S1Y标准汉字字库芯片完全解析&#xff08;1&#xff09; 本文内容参考&#xff1a; 字库芯片GT20L16S1Y使用记录-CSDN博客 GT20L16S1Y字库IC驱动_gt20l16s1y字库芯片测试程序-CSDN博客 《GT20L16S1Y 标准点阵汉字库芯片产品规格书 V4.0I_K 2…

Day45:WEB攻防-PHP应用SQL二次注入堆叠执行DNS带外功能点黑白盒条件

目录 PHP-MYSQL-二次注入-DEMO&74CMS DEMO-用户注册登录修改密码 CMS-74CMS个人中心简历功能 PHP-MYSQL-堆叠注入-DEMO&CTF强网 Demo 2019强网杯-随便注&#xff08;CTF题型&#xff09; PHP-MYSQL-带外注入-DEMO&DNSLOG(让服务器主动把数据交出去) 知识点&…

C#,图论与图算法,输出无向图“欧拉路径”的弗勒里(Fleury Algorithm)算法和源程序

1 欧拉路径 欧拉路径是图中每一条边只访问一次的路径。欧拉回路是在同一顶点上开始和结束的欧拉路径。 这里展示一种输出欧拉路径或回路的算法。 以下是Fleury用于打印欧拉轨迹或循环的算法(源)。 1、确保图形有0个或2个奇数顶点。2、如果有0个奇数顶点,则从任意位置开始。…

I2C系列(三):软件模拟I2C读写24C04

一.目标 PC 端的串口调试软件通过 RS-485 与单片机通信&#xff0c;控制单片机利用软件模拟 I2C 总线对 EEPROM&#xff08;24C04&#xff09; 进行任意读写。 二.RS-485简述 在工业控制领域&#xff0c;传输距离越长&#xff0c;要求抗干扰能力也越强。由于 RS-232 无法消除…

【复杂网络建模】——XGI库进阶学习:生成随机超图

目录 一、构建随机超图 二、绘制随机超图 三、其他功能 3.1 访问超图的最大阶 3.2 列出所有边尺寸 3.3 边大小的直方图 3.4 节点度直方图 一、构建随机超图 XGI&#xff08;eXtensible Graphs and Hypergraphs&#xff09;是一个Python库&#xff0c;专注于超图&#…

ARM CPU的总线发展

ARM架构是当今世界上最为广泛应用的嵌入式处理器架构之一&#xff0c;其CPU总线的发展对于系统性能和扩展性具有重要影响。本文将探讨ARM CPU总线的发展历程、关键技术和对系统性能的影响。 以下是我整理的关于嵌入式开发的一些入门级资料&#xff0c;免费分享给大家&#xff…

Flutter学习10 - Json解析与Model使用

对于网络请求返回的 Json 数据&#xff0c;一般会进行如下解析&#xff1a; 将 Json String 解析为 Map<String, dynamic>将 Json String 解析为 Dart Model 发起一个返回 Json String 的网络请求 import package:http/http.dart as http;void main() {_doGet(); }_do…

计算机网络——26通用转发和SDN

通用转发和SDN 网络层功能&#xff1a; 转发&#xff1a; 对于从某个端口 到来的分组转发到合适的 输出端口路由&#xff1a; 决定分组从源端 到目标端的路径 网络层 传统路由器的功能 每个路由器(Per Route)的控制平面 &#xff08;传统&#xff09; 每个路由器上都有实…

本地运行环境工具UPUPWANK(win)和Navicat数据库管理工具

UPUPWANK安装地址&#xff1a;https://www.upupw.net 1.进入UPUPWANK后点击一键开启 2.新增项目 这里请千万注意80端口&#xff0c;如果80端口被占用了&#xff0c;请记住去任务管理器关闭占用80端口的进程。不然就不会成功显示。&#xff08;笔者含泪警告&#xff0c;一晚上的…

2024年C语言最新经典面试题汇总(11-20)

C语言文章更新目录 C语言学习资源汇总&#xff0c;史上最全面总结&#xff0c;没有之一 C/C学习资源&#xff08;百度云盘链接&#xff09; 计算机二级资料&#xff08;过级专用&#xff09; C语言学习路线&#xff08;从入门到实战&#xff09; 编写C语言程序的7个步骤和编程…

Day44:WEB攻防-PHP应用SQL盲注布尔回显延时判断报错处理增删改查方式

目录 PHP-MYSQL-SQL操作-增删改查 PHP-MYSQL-注入函数-布尔&报错&延迟 基于布尔的SQL盲注-逻辑判断(需要有回显,没回显搞不了)跟union需要的条件差不多 基于时间的SQL盲注-延时判断(不需要任何回显) 基于报错的SQL盲注-报错回显(需要报错回显&#xff0c;没报错回…

算法系列--链表刷题(二)

&#x1f495;"轻舟已过万重山"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;算法系列–链表刷题(二) 今天为大家带来的是算法系列--链表刷题(二),带来了几道经典的有关链表的面试题(合并K个有序列表) 1.两数相加 https://leetcode.cn/problems/a…

短视频素材网站去哪里找?

嘿&#xff0c;各位视频创作者们&#xff01;想知道短视频素材网站去哪里找&#xff1f;今天就来给大家介绍几个必备的视频素材网站&#xff0c;特别是对于入门新手和运营人员来说&#xff0c;这些网站可是必不可少的资源哦&#xff01; 首先&#xff0c;我们来看看那些提供可…

FreeRtos时间管理(一)

FreeRtos的时间管理包括相对延时vTaskDelay、绝对延时vTaskDelayUntil、系统时钟Systick 本篇主要分析相对延时vTaskDelay函数 调用vTaskDelay是一定会触发任务切换的&#xff0c;需要分析下PendSv中断触发的位置。 一、 函数流程 二 、prvAddCurrentTaskToDelayedList 注意&…