结构体类型详细讲解(附带枚举,联合)

前言:

如果你还对结构体不是很了解,那么本篇文章将会从 为什么存在结构体,结构体的优点,结构体的定义,结构体的使用与结构体的大小依次介绍,同样会附带枚举与联合体

 

目录

 为什么存在结构体:

 结构体的优点

结构体的定义 

结构体的使用

方法一:

方法二   函数传值打印

方法三  函数传址打印   两种打印方法

第二种是利用->  这里的 ->就相当于(*).

方法四  跟方法三差不多,不利用函数打印 

结构体的typedef 

 结构体的大小计算

 ⾸先得掌握结构体的对⻬规则:

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处

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

Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

先解决对其数问题

 枚举

 枚举的使用案例

联合体(也叫共用体)


 为什么存在结构体:

当一个整体由多个数据构成时,于是人们就创造了数组,我们用数组来表示这个整体,但是数组有个特点:内部的每一个元素都必须是相同类型的数据。 ☀ 在实际应用中,我们通常需要由不同类型的数据来构成一个整体,比如学生这个整体可以由姓名、年龄、身高等数据构成,这些数据都具有不同的类型,姓名可以是字符串类型,年龄可以是整型,身高可以是浮点型。 ☀ 为此,C语言专门提供了一种构造类型来解决上述问题,这就是结构体,它允许内部的元素是不同类型的

 结构体的优点

 

  • 可以在一个结构中声明不同的数据类型。
  • 相同结构的结构体变量是可以相互赋值的。
  • 结构体的存储方式可以提高CPU对内存的访问速度。
  • 结构体可以将同一对象的多个数据类型存储在一起,方便数据的存储和处理。
  • 可以通过结构体变量名和成员名来访问数据。
  • 可以定义结构体数组,方便批量处理数据。

那么有有优点就会有缺点:

  • 如果项目的复杂性增加,管理所有数据成员就变得很困难 。
  • 对程序中的一个数据结构进行更改需要在其他几个地方进行更改。 所以很难跟踪所有的变化。
  • 结构体需要更多的存储空间,因为它为所有数据成员分配内存,甚至速度更慢。
  • 结构体占用更多存储空间,因为它为所有不同的数据成员提供内存,而联合仅占用最大数据大小参数所需的内存大小,并且与其他数据成员共享相同的内存。

结构体的定义 

 一般结构体定义便是如下

struct stu
{
	//变量成员
};

这里的struct是必不可少的部分,而stu是我们自拟定的,里面便是填充的变量成员

这个结构体就是struct stu类型的

同理下面这个结构体就是struct st类型的

struct st
{
	//变量成员
};

 这时候我们便可以在里面填充成员

比如这样

struct st
{
	int a;
    char b;
    struct st* ps;//也可以填充这个类型的指针
};

那么结构体定义完后,我们开始讲解怎么去使用

结构体的使用

这里的s为变量名 

struct st
{
    int a;
    char b; 
};
int main()
{
    struct st s = { 10,'b' };//初始化
    return 0;
}

 接下来介绍打印

方法一:

struct st
{
    int a;
    char b; 
};
int main()
{
    struct st s = { 10,'b' };//初始化
    printf("%d %c", s.a, s.b);
    return 0;
}

 

方法二   函数传值打印

struct st
{
    int a;
    char b; 
};
void print(struct st ps)
{
    printf("%d %c", ps.a, ps.b);
}
int main()
{
    struct st s = { 10,'b' };//初始化
    print(s);
    return 0;
}

 

方法三  函数传址打印   两种打印方法

第一种的打印是利用解引用

第二种是利用->  这里的 ->就相当于(*).

struct st
{
    int a;
    char b; 
};
void print(struct st* ps)
{
    printf("%d %c\n", (*ps).a, (*ps).b);
    printf("%d %c\n", ps->a, ps->b);
}
int main()
{
    struct st s = { 10,'b' };//初始化
    print(&s);
    return 0;
}

方法四  跟方法三差不多,不利用函数打印 

struct st
{
    int a;
    char b; 
};
int main()
{
    struct st s = { 10,'b' };//初始化
    struct st* ps = &s;
    printf("%d %c\n", (*ps).a, (*ps).b);
    printf("%d %c\n", ps->a, ps->b);
    return 0;
}

结构体的typedef 

 当一个结构体类型的类型名过于长的时候,我们不免过于不想去写,这时候就可以用typedef

(重命名)使用起来很简单

typedef struct st
{
    int a;
    char b; 
}st;
int main()
{
    struct st s = { 10,'b' };//初始化
    //等价于
    st s = { 10,'b' };//
    return 0;
}

 结构体的大小计算

先举例一个代码

代码跑出来这个结构体大小是8 

那么怎么计算的呢?  其原理就是对其原则

 ⾸先得掌握结构体的对⻬规则:

1.结构体的第⼀个成员对⻬到和结构体变量起始位置偏移量为0的地址处

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

Linux中gcc没有默认对⻬数,对⻬数就是成员⾃⾝的⼤⼩

3.结构体总⼤⼩为最⼤对⻬数(结构体中每个成员变量都有⼀个对⻬数,所有对⻬数中最⼤的)的整数倍。

4.如果嵌套了结构体的情况,嵌套的结构体成员对⻬到⾃⼰的成员中最⼤对⻬数的整数倍处,结构 体的整体⼤⼩就是所有最⼤对⻬数(含嵌套结构体中成员的对⻬数)的整数倍。

 

我们计算一下这个结构体大小 

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

先解决对其数问题

char    自身对齐数为1  vs上默认对齐数为8    实际取小的   那么最后为1

int 为4 

 偏移量

在C语言中,偏移量通常指的是结构体中成员变量相对于结构体起始地址的偏移量。假设有一个结构体定义如下:

struct Person {
    int id;
    char name[20];
    int age;
};

假设struct Person p;是一个Person类型的结构体变量,我们可以通过&p.id&p.name&p.age来获取各个成员变量的地址。偏移量就是从结构体起始地址到成员变量地址的字节偏移量。

例如,假设&p表示结构体p的起始地址,&p.id表示id成员变量的地址,那么&p.id - &p就是id相对于结构体起始地址的偏移量。在C语言中,可以使用指针和强制类型转换来计算偏移量,例如:

int offset = (char *)&p.name - (char *)&p;

 这样就可以得到name成员变量相对于结构体p的偏移量。偏移量在一些底层编程中经常用来访问结构体中的特定成员变量,尤其是在处理二进制数据或者硬件寄存器时非常有用。

画图表示如下

 那么我们进行利用图进行计算

typedef struct st
{
    char c1;
    int i;
    char c2; 
}st;
int main()
{
    printf("%zd", sizeof(st));
    return 0;
}

第一个char偏移量为0放于第一个,int放于偏移量为4的整数倍数处  ,最后一个char偏移量为1,放于1的整数倍数处,

用图表示如下

图上的大小一共占了9个字节,

然后我们进行最后一步 最大对齐数为4  而9不是最大对齐数的整数倍   所以要浪费3个字节补充该结构体大小到12;

那么最大怎么算了就可以解答上面那个问题为什么是8

//练习3 
struct S3
{
 double d;
 char c;
 int i;
};
printf("%d\n", sizeof(struct S3));
//练习4-结构体嵌套问题 
struct S4
{
 char c1;
 struct S3 s3;
 double d;
};
printf("%d\n", sizeof(struct S4));

答案分别是16    32         

 枚举

 在《C语言深度剖析》这本书中留有一个问题,枚举变量的大小是多少?

大家猜一下大小为多少

enum Color
{
    GREEN = 1,
    RED,
    BLUE,
    GREEN_RED = 10,
    GREEN_BLUE,
    sss,
}c;
int main()
{
    printf("%zd", sizeof(c));
}

答案是4,为啥呢?

因为,枚举变量的取值为花括号内的任意一个值(有且只能有其中一个值),而这个值是int型的,在X86系统中,int型的数据占内存4个字节。所以sizeof(c) = 4,也就是枚举变量的值为4。

 枚举的使用案例

当我们写菜单的时候,会用到switch语句

当我们写case是一般会用到case 1: case 2:

但如果功能一旦多我们就会分不清该case  要实现哪一项功能

这时候就可以用到枚举  就比如通讯录

enum option
{
	EXIT,//等价于0
	ADD,//1
	DEL,//2
	SEARCH,//3
	MODIFY,//4
	SHOW, //5
	SORT,//6
	SAVE,//7
};

void menu()
{
	printf("**************************************\n");
	printf("*****    1.add        2.del      *****\n");
	printf("*****    3.search     4.modify   *****\n");
	printf("*****    5.show       6sort      *****\n");
	printf("*****    7.save       0.exit     *****\n");
	printf("**************************************\n");
}
int main()
{
	do {
		menu();
		printf("请输入你的选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case ADD:
			Addcontact(&con);
			break;
		case DEL:
			Delcontact(&con);
			break;
		case SEARCH:
			Searchcontact(&con);
			break;
		case MODIFY:
			Modifycontact(&con);
			break;
		case SHOW:
			Showcontact(&con);
			break;
		case SORT:
			SortContact(&con);
			break;
		case SAVE:
			SaveContact(&con);
			break;
		case EXIT:
			SaveContact(&con);
			DestroyContact(&con);
			printf("退出通讯录\n");
			break;
		default:
			printf("输入错误,请重新输入:>\n");
			break;
		}

	} while (input);
	return 0;
}

联合体(也叫共用体)

 联合的成员是共⽤同⼀块内存空间的,这样⼀个联合变量的⼤⼩,⾄少是最⼤成员的⼤⼩(因为联合 ⾄少得有能⼒保存最⼤的那个成员)。

那么看以下代码

发现三者的空间是共用一块空间,所以这也对应了名字共用体,公用一块空间

 

#include <stdio.h>
union Un
{
 char c;
 int i;
};
int main()
{
 //联合变量的定义 
 union Un un = {0};
 un.i = 0x11223344;
 un.c = 0x55;
 printf("%x\n", un.i);
 return 0;
}

既然公用一块空间那么(小端)

这个代码运行结果如何呢?

我们发现将i的第4个字节的内容修改为55了(其实是改的低地址处的数据)

同样大端下会打印55223344; 

利用联合体写一个函数判断机器为大端还是小端

int check_sys()
{
 union
 {
 int i;
 char c;
 }un;
 un.i = 1;
 return un.c;//返回1是⼩端,返回0是⼤端 
}

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

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

相关文章

毕业设计:日志记录编写(3/17起更新中)

目录 3/171.配置阿里云python加速镜像&#xff1a;2. 安装python3.9版本3. 爬虫技术选择4. 数据抓取和整理5. 难点和挑战 3/241.数据库建表信息2.后续进度安排3. 数据处理和分析 3/17 当前周期目标&#xff1a;构建基本的python环境&#xff1a;运行爬虫程序 1.配置阿里云pytho…

【C++】如何用一个哈希表同时封装出unordered_set与unordered_map

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.哈希桶源码 2.哈希…

(三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练

这里写目录标题 一、colmap解算数据放入高斯1. 将稀疏重建的文件放入高斯2. 将稠密重建的文件放入高斯 二、vkitti数据放入高斯 一、colmap解算数据放入高斯 运行Colmap.bat文件之后&#xff0c;进行稀疏重建和稠密重建之后可以得到如下文件结构。 1. 将稀疏重建的文件放入高…

windows10 WSL启动Ubuntu虚拟机,安装DolphinScheduler

文章目录 1. 启动WSL与虚拟机2. 安装Docker与DolphinScheduler容器 1. 启动WSL与虚拟机 使用管理员权限运行命令&#xff1a; Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux重启后即可创建虚拟机 在Microsoft Store中搜索Ubuntu&…

Wear-Any-Way——可控虚拟试衣一键试穿,可自定义穿着方式

概述 Wear-Any-Way 是阿里巴巴最新推出的虚拟试衣技术&#xff0c;它不仅可以让用户在虚拟环境中试穿衣服&#xff0c;还可以根据需要自定义衣服的样式&#xff0c;比如卷起袖子、打开或拖动外套等。这种技术的引入旨在帮助消费者更好地了解衣服在不同穿着方式下的效果&#x…

一个python实现的kline-chart图表程序(二)

前面一中简单介绍了kline-chart的图表程序&#xff0c;实际上这个程序最主要的功能不是显示K线&#xff0c;因为显示K线的程序太多了&#xff0c;没必要专门重写&#xff0c;这个程序最主要的功能是根据需要显示包含K线在内的各种指标&#xff0c;自己算的指标&#xff0c;或是…

plSql 大批量数据导入到表中

主要2种思路&#xff0c;一为insert插入sql&#xff0c;二是借助plsql提供的工具 insert语句odbc importer/导入器 insert语句 把要插入的数据转为insert语句&#xff0c;直接复制到plsql的sql窗口&#xff0c;运行即可&#xff1b;或者在命令行窗口回车键&#xff0c;选择要执…

使用 RunwayML 对图像进行 Camera 操作

RunwayML 是一個功能強大的平台&#xff0c;可以讓您使用 AI 和机器学习来增强您的图像和视频。 它提供一系列预训练模型&#xff0c;可用于各种任务&#xff0c;包括图像编辑、风格化和特效。 在本文中&#xff0c;我们将介绍如何使用 RunwayML 对图像进行 Camera 操作。我们…

[AIGC] SQL中的数据添加和操作:数据类型介绍

SQL&#xff08;结构化查询语言&#xff09;作为一种强大的数据库查询和操作工具&#xff0c;它能够完成从简单查询到复杂数据操作的各种任务。在这篇文章中&#xff0c;我们主要讨论如何在SQL中添加&#xff08;插入&#xff09;数据&#xff0c;以及在数据操作过程中&#xf…

数据结构(五)——树森林

5.4 树和森林 5.4.1 树的存储结构 树的存储1&#xff1a;双亲表示法 用数组顺序存储各结点&#xff0c;每个结点中保存数据元素、指向双亲结点(父结点)的“指针” #define MAX_TREE_SIZE 100// 树的结点 typedef struct{ElemType data;int parent; }PTNode;// 树的类型 type…

学习或复习电路的game推荐:nandgame(NAND与非门游戏)、Turing_Complete(图灵完备)

https://www.nandgame.com/ 免费 https://store.steampowered.com/app/1444480/Turing_Complete/ 收费&#xff0c;70元。据说可以导出 Verilog &#xff01;

关于安卓调用文件浏览器(一)打开并复制

背景 最近在做一个硬件产品&#xff0c;安卓应用开发。PM抽风&#xff0c;要求从app打开文件浏览器&#xff0c;跳转到指定目录&#xff0c;然后可以实现文件复制粘贴操作。 思考 从应用开发的角度看&#xff0c;从app打开系统文件浏览器并且选择文件&#xff0c;这是很常见…

馆室一体化查档平台制度有哪些

馆室一体化查档平台制度是指图书馆或档案馆在数字化和信息化的背景下&#xff0c;建立起的集查阅、借阅、咨询、文献传递等多项功能于一体的平台制度。下面是一些常见的馆室一体化查档平台制度&#xff1a; 1. 馆藏管理制度&#xff1a;包括图书和档案的采购、编目、分类、整理…

那些王道书里的题目-----计算机网络篇

注&#xff1a;仅记录个人认为有启发的题目 p155 34.下列四个地址块中&#xff0c;与地址块 172.16.166.192/26 不重叠&#xff0c;且与172.16.166.192/26聚合后的地址块不会引入多余地址的是&#xff08;&#xff09; A.172.16.166.192/27 B.172.16.166.128/26 …

day06vue2学习

day06 路由的封装抽离 问题&#xff1a;所有的路由配置都堆在main.js中不太合适么&#xff1f;不好&#xff0c;会加大代码的复杂度 目标&#xff1a;将路由模块抽离出来。好处&#xff1a;差分模块&#xff0c;利于维护。 大致的做法就是&#xff0c;将路由相关的东西都提…

codeTop102:二叉树的层序遍历

前言 在已知BFS的方式后&#xff0c;知道每次从队列中取一个节点&#xff0c;就要将这个节点的所有子节点按照顺序放入队列。 难点在于怎么确定将同一层的节点放在一个数组里面的输出&#xff0c;也就是输出一个二维数组&#xff1f; 解决方法: 每次while循环将队列上轮放入的…

蓝桥集训之矩形牛棚

蓝桥集训之矩形牛棚 核心思想&#xff1a;单调队列 模板&#xff1a;Acwing.131.直方图矩形面积首先遍历所有下界 然后确定以该下界为底的直方图 求最大矩形 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 30…

Java学习day2

命名规则 在JAVA中&#xff0c;公共类的明朝必须与包含该类的源文件的文件名向匹配&#xff0c;即 这两个名称要一致 变量类型 与c/c基本一致 需要注意的是&#xff0c;long类型的数据在后面需要加上l或L&#xff08;建议加L&#xff0c;l可能会被误判&#xff09;&#xff…

【Redis】优惠券秒杀

全局唯一ID 全局唯一ID生成策略&#xff1a; UUIDRedis自增snowflake算法数据库自增 Redis自增ID策略&#xff1a;每天一个key&#xff0c;方便统计订单量ID构造是 时间戳 计数器 Component public class RedisIdWorker {// 2024的第一时刻private static final long BEGIN…

【C语言】编译和链接----预处理详解【图文详解】

欢迎来CILMY23的博客喔&#xff0c;本篇为【C语言】文件操作揭秘&#xff1a;C语言中文件的顺序读写、随机读写、判断文件结束和文件缓冲区详细解析【图文详解】&#xff0c;感谢观看&#xff0c;支持的可以给个一键三连&#xff0c;点赞关注收藏。 前言 欢迎来到本篇博客&…