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

news2024/11/18 20:35:43

目录

结构体

结构体的使用方法

结构体所占用的大小

位段

位段的使用方法

位段所占用的大小

枚举常量

枚举常量的使用方法

枚举常量的优势

联合体

联合体的使用方法

结构体

结构体的使用方法

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

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

我们写一段这样的代码

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

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

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

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

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

相关文章

Pink老师Echarts教学笔记

可视化面板介绍 ​ 应对现在数据可视化的趋势&#xff0c;越来越多企业需要在很多场景(营销数据&#xff0c;生产数据&#xff0c;用户数据)下使用&#xff0c;可视化图表来展示体现数据&#xff0c;让数据更加直观&#xff0c;数据特点更加突出。 01-使用技术 完成该项目需…

TCP(socket 套接字)编程 1

一、TCP套接字编程架构如下 二、相关代码实现 1、服务器端代码 package com.company;import java.io.IOException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket;public class Main {public static void main(String[] args) {…

GeoAI

GeoAI 是人工智能 (AI) 与空间数据、科学和地理空间技术的集成&#xff0c;以增进对空间问题的理解和解决。GeoAI 包括应用传统人工智能技术&#xff0c;通过从结构化和非结构化数据中提取、分类和检测信息来生成空间数据。GeoAI 也是空间显式人工智能技术的使用&#xff0c;旨…

超越工具的限制!菜鸟工具箱帮你节省时间

在这个飞速发展的时代&#xff0c;我们越来越依赖各种工具来提高工作效率和解决问题。然而&#xff0c;你是否意识到&#xff0c;有些工具不仅仅是工具&#xff0c;它们还能为你带来更多的可能性和机遇&#xff1f;菜鸟工具箱就是这样一个超越工具本身的存在&#xff01; 菜鸟工…

政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(二)—— 深度神经网络

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras实战演绎 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 概述 深度神经网络&#xff08;Deep Neural Network…

扩展一下BenchmarkSQL,新增支持ASE/HANA/DB2/SQLServer,可以随便用了

1 背景 提到数据库的性能,自然就避不开性能测试。有专用于测试OLTP的,也有偏重于OLAP的。本文介绍的BenchmarkSQL就属于测试OLTP中的一个,基于TPCC的。网上有很多介绍TPC*的相关测试的文章,大家可以自行脑补。而PostgreSQL自带的pgbench是属于TPCC的前一个基准测试程序,偏…

【Linux系统编程(进程编程)】创建进程的场景,fork和vfork的使用及区别

文章目录 一、进程关键概念二、创建进程函数fork的使用一、进程创建实战 三、创建进程函数fork的使用补充四、进程创建发生了什么事&#xff1f;五、创建新进程的实际应用场景 & fork总结一、fork创建一个子进程的一般目的&#xff1f;二、fork编程实战 六、vfork也能创建进…

Day55-LNMP架构原理及实战精讲

Day55-LNMP架构原理及实战精讲 1.什么是LNMP?2.LNMP架构工作原理流程解析3.LNMP架构环境安装部署4. LNMP架构配置及整体测试实战5. 超越企业级标准搭建和优化blog软件5.1 部署博客blog软件5.2 部署知乎软件Wecenter 1.什么是LNMP? 2010年前 LAMP Linux、Apache、MySQL、PHP&…

能降低嵌入式系统功耗的三个技术

为电池寿命设计嵌入式系统已经成为许多团队重要的设计考虑因素。优化电池寿命的能力有助于降低现场维护成本&#xff0c;并确保客户不需要不断更换或充电电池&#xff0c;从而获得良好的产品体验。 团队通常使用一些标准技术来提高电池寿命&#xff0c;例如将处理器置于低功耗…

企业微信可以更换公司主体吗?

企业微信变更主体有什么作用&#xff1f;当我们的企业因为各种原因需要注销或已经注销&#xff0c;或者运营变更等情况&#xff0c;企业微信无法继续使用原主体继续使用时&#xff0c;可以申请企业主体变更&#xff0c;变更为新的主体。企业微信变更主体的条件有哪些&#xff1…

上位机图像处理和嵌入式模块部署(qmacvisual图像识别)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 所谓图像识别&#xff0c;就是对图像进行分类处理&#xff0c;比如说判断图像上面的物体是飞机、还是蝴蝶。在深度学习和卷积神经网络CNN不像现在这…

2024-03-23 作业

网络聊天室 运行代码&#xff1a; main.c #include "link.h" #define SER_PORT 8888 int main(int argc, const char *argv[]) {if(argv[1]NULL){printf("请输入IP地址\n");return 0;}//创建套接字文件int sfd socket(AF_INET,SOCK_DGRAM,0);if(sfd …

【计算机网络】常见面试题汇总

文章目录 1.计算机网络基础1.1网络分层模型/OSI七层模型是什么&#xff1f;1.2TCP/IP四层模型是什么&#xff1f;每一层的作用&#xff1f;1.2.1TCP四层模型&#xff1f;1.2.2为什么网络要分层&#xff1f; 1.2常见网络协议1.2.1应用层常见的协议1.2.2网络层常见的协议 2.HTTP2…

MongoDB知识

1、部署MongoDB &#xff08;1&#xff09;new好一个mongo文件之后执行 &#xff08;出现mongodb.key&#xff09;记得放行端口 openssl rand -base64 666 > mongodb.key &#xff08;2&#xff09;放到一个docker-compose.yml之后docker-compose up -d执行 version: 3.…

数学(算法竞赛、蓝桥杯)--快速幂

1、B站视频链接&#xff1a;G01 快速幂_哔哩哔哩_bilibili 题目链接&#xff1a;P1226 【模板】快速幂 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include <bits/stdc.h> using namespace std; typedef long long LL; int a,b,p; int quickpow(LL a,int n,int p){…

【wails】(10):研究go-llama.cpp项目,但是发现不支持最新的qwen大模型,可以运行llama-2-7b-chat

1&#xff0c;视频演示地址 2&#xff0c;项目地址go-llama.cpp 下载并进行编译&#xff1a; git clone --recurse-submodules https://github.com/go-skynet/go-llama.cpp cd go-llama.cpp make libbinding.a项目中还打了个补丁&#xff1a; 给 编译成功&#xff0c;虽然有…

力扣面试150 阶乘后的零 数论 找规律 质因数

Problem: 172. 阶乘后的零 思路 &#x1f468;‍&#x1f3eb; 大佬神解 一个数末尾有多少个 0 &#xff0c;取决于这个数 有多少个因子 10而 10 可以分解出质因子 2 和 5而在阶乘种&#xff0c;2 的倍数会比 5 的倍数多&#xff0c;换而言之&#xff0c;每一个 5 都会找到一…

vue3与Electron构建跨平台应用(webpack)

一、创建vue3项目 vue create vue3_webpack_electron 二、安装Electron npm install --save-dev electron Electron 三、vue add electron-builder vue add electron-builder

VMware中UbuntuServer扩展硬盘空间

VMware中UbuntuServer扩展硬盘空间 没有不可治愈的伤痛&#xff0c;没有不能结束的沉沦&#xff0c;所有失去的&#xff0c;会以另一种方式归来 ——【约翰-肖尔斯】 第一步 lxalxa:~$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS loop0 …

鸿蒙Harmony应用开发—ArkTS-像素单位

ArkUI为开发者提供4种像素单位&#xff0c;框架采用vp为基准数据单位。 说明&#xff1a; 本模块首批接口从API version 7开始支持&#xff0c;后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 名称描述px屏幕物理像素单位。vp屏幕密度相关像素&#xff0c;…