Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【C结构体】结构体都不会,学啥数据结构(进阶版)

【C结构体】结构体都不会,学啥数据结构(进阶版)

作者头像
MicroFrank
发布于 2023-01-16 03:56:17
发布于 2023-01-16 03:56:17
51300
代码可运行
举报
文章被收录于专栏:同步文章1234同步文章1234
运行总次数:0
代码可运行
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
                       智者不为情所困

文章目录

  • 一.结构体
    • 1-1结构体类型的声明
    • 1-2结构体的自引用
    • 1-3结构体变量的定义和初始化
    • 1-4结构体内存对齐(求结构体所占字节数)
    • 1-5结构体传参
    • 1-6结构体实现位段(bit field)

一.结构体

  • 数据经常会以组的形式存在,例如:用结构体描述一个复杂对象的基本信息–学生,这些值能够存储在一起,访问起来就会简单一些,但是由于这些值的类型互不相同,则无法使用数组存储,因此便有了结构体

1-1结构体类型的声明

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
用结构体描述一个复杂对象的基本信息:学生
struct Stu
{//Stu是结构体标签,struct Stu才是结构体类型,相当于int
	char name[20];名字
	int age;年龄
	char sex[2];性别
	char id[20];学号
};分号不能丢

数组元素可以通过下标访问,是因为数组的元素长度相同,但是结构体的成员变量的类型不同,因此不能使用下标访问结构体的成员变量

1-2结构体的自引用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
正确的结构体自引用:结构体的
struct Stu1
{
	int a;
	char b;
	struct Stu1* c;结构体指针变量
};


错误的结构体自引用:
struct Stu2
{
	int a;
	char b;
	struct Stu2 c;结构体
};

结构体包含一个类型为该结构体本身的成员是非法的,有点像永不终止的递归程序; 但是结构体内部包含一个指向该结构体本身的指针是合法的,在单链表中很常见

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
单链表中结构体中包含结构体指针的使用:
typedef struct Node
{
	int date;
	struct Node* ps;但不能写成ListNode* ps
//因为这个typedef声明的类型名直到声明的末尾才被定义
}ListNode;

此处的typedef是给struct Node进行了类型重命名,也类似于int,以后就可以直接用Node定义结构体变量

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef类型重命名前定义结构体变量:
struct Node newnode;

typedef类型重命名后定义结构体变量:(是不是少些了个struct,适当偷懒)
ListNode newnode;

1-3结构体变量的定义和初始化

结构体的初始化方式和数组的初始化方式很像,结构体成员是否包含数组分别对于一维和二维数组的初始化很像

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct Stu
{
	char name[20];
	int age;
	char sex[2];
}student1={{宋小宝},18,};
  • 结构体的成员变量不能是结构体本身,但是可以是另一个结构体
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
typedef struct date
{
	int year;
	int month;
	int day;
}Date;

struct Stu
{
	Date a;
	int number;
};
  • 图解:

1-4结构体内存对齐(求结构体所占字节数)

什么是偏移量和对齐数?

  • 偏移量:相对于第一位置存放开始,到第二个位置存放开始之间的地址差
  • 偏移量可以使用offsetof宏来求得(定义与stddef.h)
  • offsetof(type,member)例子即是offsetof(struct Stu,age)
  • 对齐数:该成员变量的字节数和编译器默认对齐数(VS默认是8)中的最小值
  • 每一个成员变量都有自己的对齐数

结构体内存对齐规则:

  1. 第一个成员在与结构体变量偏移量为0的地址处
  2. 从第二个成员开始的每个成员变量要对齐到对齐数的整数倍处
  3. 结构体的整体大小就是最大对齐数的整数倍
  4. 如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍中,结构体的整体大小就是所有最大对齐数的整数倍

概念麻烦,实际简单的一批

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
给你举个例子画个图吧
struct AKIGN
{
	char a;第一个数不用考虑内存对齐,直接放
	int b;第二个数放的位置(偏移量)要是int字节(4)的整数倍,也就是4
	char c;第三个数放的位置(偏移量)要是char字节(1)的整数倍,也就是9
};

由于结构体的整体大小就是所有最大对齐数(这里是4)的整数倍,所以结果总共是占12个字节

  • 图解:

总之就是要综合考虑数据类型和偏移量,匹配整数倍就可以啦,是不是很简单

为什么存在内存对齐? 1.1、平台原因:不是所有的硬件平台都能访问任意地址上的任意数据,某些硬件平台只能在某些地址处取某些特定类型的数据 2、性能原因:,对于访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问,使得处理起来速度快。 本质: 空间换时间\ 怎样设计可以减少空间浪费? 使得空间小的成员尽量集中在一起

学会了?来几道测试题?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 练习2
struct S2
{
	char c1;   1
	char c2;   1-2
	int i;     4-8
};
printf("%d\n", sizeof(struct S2));//要是double(8)个字节的整数倍,答案:占8个字节
//练习3
struct S3
{
	double d;     1-8
	char c;       9
	int i;        12-16
};
printf("%d\n", sizeof(struct S3));//要是double(8)个字节的整数倍,答案:占16个字节
//练习4-结构体嵌套问题
//如果嵌套了结构体,嵌套的结构体对齐到自己的最大对齐数的整数倍中
struct S4
{
	char c1;           1
	struct S3 s3;      8-16
	double d;          16-24
};
printf("%d\n", sizeof(struct S4));//要是double(8)个字节的整数倍,答案:占24个字节

修改默认对齐数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#pragma pack(4)//设置默认对齐数为4
struct S1
{
 char c1;
 double i;默认对齐数(4)和成员变量的字节数(8)比较取最小的为默认对齐数(4):4个字节
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
#pragma pack(1)//设置默认对齐数为8
struct S2
{
 char c1;
 int i;
 char c2;
};
#pragma pack()//取消设置的默认对齐数,还原为默认
int main()
{
    //输出的结果是什么?
    printf("%d\n", sizeof(struct S1));答案是16个字节
    printf("%d\n", sizeof(struct S2));答案是6个字节
    return 0;
}

1-5结构体传参

结构体传参的两种方式:(不考虑效率而言)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1.传结构体本身:
print_struct(struct Stu);

2.传结构体地址:
print_struct(&struct Stu);

关于效率高的传参方式:传结构体指针

  1. 函数形参要压栈,而结构体指针相对占用栈内存小
  2. 如果希望传过去修改成员,则只有传结构体指针
  3. 如果不希望被修改也可以使用const修饰,进行保护
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct S
{
 int data[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* ps)
{
 printf("%d\n", ps->num);
}
int main()
{
 print1(s);  //传结构体
 print2(&s); //传地址
 return 0;
}

1-6结构体实现位段(bit field)

有的时候我们存放的一个数据并不需要一个字节那么大的空间,而只需要几个比特位就够了,比如我们用二进制表示灯泡的开关,只需要0和1就足够表示这两种状态,那么怎么实现这样减少空间的浪费呐?这就需要用到我们强大的位段。

  • 位段位段,位顾名思义就是二进制位,段就是路段,长度,综合就是二进制位的长度

位段和结构体的声明的区别:

  • 他的成员后面相对于结构体多一个冒号和整数,这个整数指定该位段所占用的位的数目。
  • 位段成员必须声明为int ,unsigned int ,signed int 或char类型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct S
{
 char a : 3;
 char b : 4;
 char c : 5;
 char d : 4;
};
int main()
{

	struct S s = { 0 };
	s.a = 10;
	s.b = 12;
	s.c = 3;
	s.d = 4;

	printf("%d\n", sizeof(struct S));
}

注意:注重可移植性的程序应该避免使用位段:(理由如下)

  1. int 位段被当成有符号数还是无符号数是不确定的。
  2. 位段中最大位的数目不能确定。(16位机器最大16,32位机器最大32,写成27,在16位机 器会出问题。
  3. 位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
  4. 当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时,是舍弃剩余的位还是利用,这是不确定的

联合体:联合体就是共用同一块内存

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<stdio.h>
union UN//如果省去UN就是匿名结构体类型,只能使用一次
{
	int a;
	char ch;
};
int main()
{
	//判断猜测:共用同一块内存
	union UN u;
	printf("%p\n", &(u.ch));//地址1
	printf("%p\n", &(u.a));//地址1
	printf("%d\n", sizeof(u));//4

	u.a = 1;
	printf("%d\n", u.a);//1
	//通过共用一块内存通过改变u.c就能改变u.a
	u.ch = 0;
	printf("%d\n", u.ch);//0

    //判断是大端还是小端
	printf("%d\n", u.ch);//0
	return 0;
}

判断机器是大端机还是小端机:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
union un
{
	int a;
	char c;
};

int test1()
{
	int n = 1;;
	return *(char*)&n;
}


int test2()
{
	union un u;
	u.a = 1;
	return u.c==1;
}

//这里都是使得int类型的变量赋值为1,也就是十六进制的都是00 00 00 01,然后通过让char或者联合本身的特点访问其中的低地址的内容,如果最低的字节内容是1,则是整数的最低字节的内容放在了低地址处,则是小端,反之。。

int main()
{
	int ret=test1();
	if (ret == 0) printf("大端\n");
	else if(ret==1) printf("小端\n");
}

计算联合体的大小: 1.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C语言】结构体
在C语言中,有两种类型,一种是内置类型,可以直接使用,包括char short int long long long float double;一种是自定义类型,当内置类型不能满足时,支持自定义一些类型,像结构体、枚举、联合体。 这次先来看看结构体。
zxctscl
2024/01/23
2120
【C语言】结构体
[C语言]结构体进阶与枚举联合
有时候我们需要将不同类型的数据组合成一个有机的整体,如:一个学生有学号、姓名、性别、年龄、地址等属性.显然单独定义以上变量比较繁琐,数据不便于管理,C语言中给出了另一种构造数据类型——结构体.
IT编程爱好者
2023/04/12
6420
[C语言]结构体进阶与枚举联合
【C语言】结构体
结构体由一系列成员(member)组成,每个成员可以是不同的数据类型。这些成员通常通过结构体的名称和点运算符来访问,结构体可以被声明为变量、指针或数组,用于存储和操作包含多种数据类型的复杂数据。在编程中,结构体常用于封装相关属性,以便于管理和使用。
用户11290673
2024/09/25
1760
【C语言】结构体
【C语言】结构体
我们在指针终篇中提到过结构体的这一部分内容(详情请阅拙作终の指针)现在我们来整个展开叙述一下
s-little-monster
2024/06/06
1180
【C语言】结构体
C语言(12)----结构体
首先我们需要知道的是结构体是一种数据类型,它本质上是用于将不同类型的数据组合在一起形成的一个新的数据类型。
Skrrapper
2024/06/18
1060
结构体(详解)
结构是⼀些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量,结构体的声明如下:
ahao
2024/03/19
1240
结构体(详解)
详解结构体--C语言
我们平时使用的C语言类型类型主要是整数类型、浮点数类型以及指针类型,你是否想过我们该如何将一串不同类型的数据整合起来,实现封装? 事实上,C语言也提供给我们一些自定义类型,让我们可以自由的进行数据组合和使用。
用户9996207
2023/01/13
1.6K0
详解结构体--C语言
打造坚实的基础:C语言的结构体、联合体和枚举
在编程中,特别是在像C和C++这样的语言中,结构体(struct)是一种用于创建复合数据类型的工具。结构体允许你将多个不同类型的数据项组合成一个单一的实体。这对于组织和管理数据非常有用,尤其是当你需要处理复杂的数据集时。
用户11029103
2024/03/19
1530
打造坚实的基础:C语言的结构体、联合体和枚举
初识C语言·自定义类型(2)
什么是结构?结构也就是元素的集合,在C语言里面,结构体里面的可以有多个变量,类似于集合中的元素,结构体里面的元素被叫做成员变量,成员变量可以是不同类型的多个变量,那么创建好结构体之后,定义的就是结构体变量,那么结构体的创建用到的是关键字struct,创建如下:
_lazy
2024/10/16
960
初识C语言·自定义类型(2)
【C语言】自定义类型(结构体、位段、枚举、联合体)
要记住结构体是一种类型,它的地位是和int这些类型是一样的,我们能用int做的事情,也可以用结构体做。唯一不同的是,结构体是通过我们自己去定义的,而int这些类型是我们c语言内置的类型
举杯邀明月
2023/04/12
6860
【C语言】自定义类型(结构体、位段、枚举、联合体)
自定义类型:结构体
结构体是一种复合数据类型,结构体将不同的数据组合成一个整体的自定义数据类型,它可以包含不同的类型成员变量,整型、浮点型、字符型等这些成员按照一定的顺序存储在内存中,每个成员都有对应的内存地址和大小。
技匠晓晨
2024/11/26
1340
自定义类型:结构体
结构体
如何计算结构体的大小,就需要知道它在内存中是如何储存的。 而结构体在内存中存在结构体对齐的现象。
code-child
2023/05/30
6340
结构体
C语言进阶-自定义类型:结构体/位段/枚举/联合
目录 前言 结构体struct 结构体的声明 结构的自引用 结构体变量的定义和初始化 空结构体大小 结构体内存对齐 修改默认对齐数 宏offsetof 结构体传参 柔性数组 struct与class的区别 位段 什么是位段 位段的内存分配 位段的跨平台问题 枚举enum 枚举类型的定义 枚举的优点 enum 与 #define 的区别 联合union 联合类型的定义 联合的特点 union和大小端 联合大小的计算 ---- 前言 ---- 本章主要讲解重点: 深入掌握结构体,枚举,联合的使用和特点,以及学会
用户9645905
2022/11/30
7300
C语言进阶-自定义类型:结构体/位段/枚举/联合
【C语言】一篇速通结构体
如上述代码这是一个结构体指针变量说明结构体指针变量p指向(->)的是一个结构体类型变量地址也就是保存x的地址。
謓泽
2023/03/01
4460
【C语言】一篇速通结构体
轻松拿捏C语言——自定义类型之【结构体】
因为⼀个结构体中再包含⼀个同类型的结构体变量,这样结构体变量的大小就会⽆穷的⼤,是不合理的
用户11162265
2024/06/14
930
【C语言】自定义类型总结
不是这样的,对于结构体的大小存在着内存对齐问题,基于此,我们首先需要了解内存对齐的规则
平凡的人1
2022/11/15
3150
【C语言】自定义类型总结
【C/自定义类型详解】——结构体(struct)、位段、枚举(enum)、联合(union)
我们通常会用一个变量来定义一个事物,就比如我们要进行求和,我们通常会创建一个sum的变量来存放求和的结果,最终再打印sum,此时的sum就表示我们最终的求和结果。
诺诺的包包
2023/02/17
1.5K0
【C/自定义类型详解】——结构体(struct)、位段、枚举(enum)、联合(union)
C语言-----自定义类型-----结构体&枚举&联合
结构体和数组一样,都是一群数据的集合,不同的是数组当中的数据是相同的类型,但是结构体中的数据类型可以不相同,结构体里的成员叫做成员变量
阑梦清川
2025/02/24
860
C语言-----自定义类型-----结构体&枚举&联合
深入理解C语言中的结构体
在C语言中,结构体(struct)是一种强大的数据组织工具,它允许你将不同类型的数据组合成一个单一的实体。无论是在处理复杂数据、设计数据模型还是进行内存优化,结构体都能帮助你更好地管理和组织数据。在本文中,我们将深入探讨C语言中的结构体。
平凡之路.
2024/10/09
3980
深入理解C语言中的结构体
C语言——结构体
在C语言中,有许多的内置类型,如char、int、double等等,但仅仅有这些类型是远远不够的。
HZzzzzLu
2024/11/26
1770
C语言——结构体
相关推荐
【C语言】结构体
更多 >
领券
💥开发者 MCP广场重磅上线!
精选全网热门MCP server,让你的AI更好用 🚀
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验