代码编织梦想

一、基础知识

1.结构体的声明

1.1结构类型的声明

关键字 自定义标识符

{

类型名1 成员名表1;

......

类型名n 成员名表n;

};

例:

struct student
{
  long num;
  char name[20];
  float score;
};

1.2结构类型变量的声明

关键字 自定义标识符 结构变量

  • 直接声明

struct student//系统只为已声明变量的结构类型分配存储空间
{
  long num;
  char name[20];
}stu1,stu2;//此结构变量占字节数:4+20=24;
  • 间接声明

struct student
{
  long num;
  char name[20];
};
struct student stu1,stu2;//关键字  自定义标识符  结构变量
  • 无类型名声明(匿名结构体)//只用一次时

struct //省去结构名,直接给出结构变量
{
  long num;
  char name[20];
}stu1,stu2;//无结构类型名,无法再次声明该结构类型的变量

😵注意:即使匿名结构体成员相同,在编译器看来也是不同类型的结构体!

struct 
{
  long num;
  char name[20];
}x;
struct 
{
  long num;
  char name[20];
}*p;
p=&x;

1.3类型重命名(较简便)

typedef struct Node
{
  int data;
  long num;
}Node,*pNode;//pNode-->struct Node*(结构体指针重命名)
int main()
{
Node n;
return 0;
}

2.结构体的自引用

👀引:数据结构:线性/树形/图

线性:顺序表 链表(数据域|指针域)

错误示例:
struct Node
{
   int data;
   struct Node n;
};
int main()
{
 struct Node n;
 return 0;
}
正确示例:
struct Node
{
int data;//数据
struct Node* next;//指针
};
!注意:错误自引用
typedef struct 
{
  int data;
  Node* next;
}Node;
int main()
{
Node n;
return 0;
}
修正:
typedef struct Node
{
  int data;
  struct Node* next;
}Node;
int main()
{
Node n;
return 0;
}

3.结构变量的初始化

struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = {10, {4,5}, NULL}; //结构体嵌套初始化
struct Node n2 = {20, {5, 6}, NULL};

4.结构体传参(待补充)

二、😈结构体内存对齐

😇引例:

struct S1 //对齐数
{
char c1;  //1
int i;    //4
char c2;  //1   //最大对齐数为4   4的倍数为12
}s1;

struct S2
{
char c1;  //1
char c2;  //1
int i;    //4   //最大对齐数为4   4的倍数为8
}s2;

2.1结构体的对齐规则:

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

  1. 其他成员变量在对齐数整数倍的地址处。

对齐数 = 编译器默认对齐数 与 成员所占字节数 的较小值

(VS中默认对齐数为8/Linux环境无默认对齐数,自身大小即为对齐数)

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

s1

s2

内存

内存

偏移量

c1

c1

0

waste

c2

1

waste

waste

2

waste

waste

3

i

i

4

i

i

5

i

i

6

i

i

7

c2

8

waste

9

waste

10

waste

11

12

2.1.1练习:

struct S3
{          //偏移量(所放位置)
double d;  //0-7
char c;    //8
int i;     //12-15      //最大对齐数为8
}s3;//16

2.1.2拓展:offsetof-宏

  1. 用途:计算结构体成员相对于起始位置的偏移量

  1. 原型:

#include<stddef.h>

size_t offsetof(structName,member name);

struct S3
{          //偏移量(所放位置)
double d;  //0-7
char c;    //8
int i;     //12-15      //最大对齐数为8
}s3;//16
printf("%u",offsetof(struct S3,d));//0  8  12

2.1.3嵌套结构体的内存对齐规则

嵌套的结构体对齐到自己最大对齐数的整数倍处,整体大小是所有最大对齐数(含嵌套结构体对齐数)的整数倍。

struct S3
{
double d;//8
char c;//1
int i;//4   //最大对齐数8
};
printf("%d\n", sizeof(struct S3));
struct S4
{
char c1;//1
struct S3 s3;//16
double d;//8         //所有对齐数最大为8
};
printf("%d\n", sizeof(struct S4));//32

偏移量

偏移量

偏移量

偏移量

偏移量

c1

0

waste

7

s3

14

s3

21

d

28

waste

1

s3

8

15

22

29

waste

2

9

16

23

30

waste

3

10

17

d

24

31

waste

4

11

18

25

32

waste

5

12

19

26

33

waste

6

13

20

27

34

2.2内存对齐的存在原因

1. 平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特

定类型的数据,否则抛出硬件异常。

2. 性能原因:

数据结构(尤其是栈)应该尽可能地在自然边界上对齐。

原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访

问。引例引用:比特鹏哥的图片讲解板书

b90428b735f44c4c85d842756e8c7857.jpeg

😷:Sum:结构体的内存对齐是拿空间来换取时间的做法。

改进:设计结构体的时候,既要满足对齐,又要节省空间,让占用空间小的成员尽量集中在一起。

2.3默认对齐数的修改

对齐方式不合适时可更改默认对齐数

struct S  字节 默认对齐数 对齐数  偏移量
{
char c;   //1    8       1       0
double d; //8    8       8      8-15
};//16
#pragma pack(4)//设置默认对齐数为4
struct S  字节 默认对齐数 对齐数  偏移量
{ 
char c;   //1    4       1        0
double d; //8    4       4      4-11
};//12
#pragma pack()//取消,还原为默认

三、位段(位指二进制位)

3.1什么是位段

位段的声明和结构类似,不同之处:

  • 1.位段的成员必须是 int、unsigned int 或signed int 。(char也可以)

  • 位段的成员名后边有一个冒号和一个数字(数字意义:该成员占用比特位数

例如:

struct A     //A就是一个位段类型
{
int _a:2;
int _b:5;
int _c:10;
int _d:30;
};//47bit
printf("%d\n", sizeof(struct A));//8bite-->2*int

3.2位段的内存分配

  • 1. 位段的成员可以是 int ,unsigned int ,signed int 或者 char (属于整形家族)类型

  • 2. 位段的空间按照需要,以4个字节( int )或1个字节( char )方式来开辟。

  • 3. 位段涉及很多不确定因素,位段是不跨平台的,注重可移植程序应避免使用位段

struct S     //剩余比特位
{            //_a是int-4byte-32bit
int _a:2;   //30
int _b:5;   //25
int _c:10;  //10
int _d:30;  //开辟一个新的4byte-不知_b是否占用原字节剩余的15bit
};
//16位机器-16bit

详细图解(图片来自比特课件)

918036fe5a4d430a84f3aba7d7c07fab.png

3.3位段的跨平台问题

  • 1. int 位段被当成有/无符号数不确定

  • 2. 位段中最大位的数目不能确定。(16位机器16,32位机器32,写成27,在16位机器会出问题)

  • 3. 位段中成员在内存中分配标准尚未定义(左-右||右-左)。

  • 4. 含两个位段的结构,第一个位段剩余位无法容纳第二个位段成员,剩余的位不确定舍弃||利用。

Sum:位段可以节省空间,但是存在跨平台的问题

3.4位段的应用

c114deb9e9e24021b5aa430960567da4.jpeg

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/LHRan_ran_/article/details/129601531

c语言_自定义类型之结构体_rugu-sco的博客-爱代码爱编程_c语言自定义结构体

即使C语言本身已经有很多种类型,但在实际应用中还是不够的,我们还需要有一些自定义的类型,例如结构体,联合,枚举 结构体 结构体的类型创建: //例如描述一个学生 struct Student //Student叫做结构

c语言怎么自定义类型,C语言自定义类型之结构体-爱代码爱编程

原创 coolmoying 1月11日 收录于话题 #C语言零基础教程 22个 前言 上一章节主要讲解的是指针的动态内存申请,三个申请函数,realloc,malloc,calloc。本章节主要是针对于结构体类型做个讲解。剩下的两种自定义类型,联合体和枚举类型下个章节做介绍。 C语言结构体 在C语言中,结构体是不同数据类型的元

自定义类型(结构体、联合(共用)、枚举)-爱代码爱编程

目录 一.结构体 1.结构体声明 2.结构体初始化  3.结构体对齐 4.修改默认对齐数 5.结构体传参  上面的 print1 和 print2 函数哪个好些?答案是:首选print2函数。原因: 6.位段  二.联合体 三.枚举 1.结构体 我们在日常生活中,经常看到这样的数据,比如: 姓名:小明 电话:139*

C语言之自定义类型—结构体-爱代码爱编程

目录         结构体 什么是结构体 结构体的声明 结构成员的类型 结构体变量的初始化和定义 特殊声明 结构的自引用 结构体成员的访问 结构体内存对齐 如何计算? 为什么存在对齐数 怎么在提高效率的同时怎么省空间 修改默认对齐数 结构体传参         位段 (依附于结构体) 位段的内存分配 位段的跨平台问题

自定义类型-结构体详解-爱代码爱编程

目录 一.结构体介绍-自定义类型二.结构体的声明1.结构体声明2.结构体变量的定义和初始化3.结构体变量访问成员4.结构体的自引用三.结构体数组四.结构体与指针及函数传参1.指向结构体变量的指针2.指针访问成员变量3.STM32寄存器映射4.结构体传参五.结构体在内存的存储1.结构体内存对齐2.内存对齐的原因3.修改默认对齐数4.实现offseto

c语言自定义类型之结构体篇_韶光初雪的博客-爱代码爱编程

自定义类型之结构体 文章目录 自定义类型之结构体结构体结构体类型的声明标题结构的自引用结构体变量的定义和初始化结构体内存对齐结构体传参结构体实现位段(位段的填充&可移植性) 结构体 结构体类型的声明 1.1结构体声明 struct tag {member-list; }variable-list; 1.2结构体特殊声

自定义类型——结构体_一只大喵咪1201的博客-爱代码爱编程

🐱作者:一只大喵咪1201 🐱专栏:《C语言学习》 🔥格言:你只管努力,剩下的交给时间! 结构体 🏆结构体的声明🏆结构体的自引用🏆结构体变量的定义和初始化🏆结构体内存对齐🏓内存对齐的原因🏓减少内存对齐导致的空间浪费🏆结构体传参🏆位段及存储🏆总结 🏆结构体的声明 基本描述 在C语言中,有很多内置类型,比如char类型,int类型,

自定义类型-结构体_xyk:小白的博客-爱代码爱编程

文章目录 一、结构体介绍-自定义类型二、结构体的声明      1.结构体声明      2.结构体变量和定义和初始化      3.结构体变量访问成员      4.结构体的自引用三、结构体传参      1.结构体数值传参      2.结构体地址传参四、结构体在内存的存储    1.结构体内存对齐    2.内存对齐的原因    3.修改默认

【c语言】自定义类型之结构体篇_小白在努力y的博客-爱代码爱编程

目录 一、结构体类型的声明 1、结构的声明 2、不完全声明 二、结构体的自引用 三、结构体变量的定义和初始化 四、结构体内存对齐 1、结构体内存对齐规则 2、为什么要对齐 3、修改默认对齐数 五、结构体传参 六、位段 1、位段是什么 2、位段的内存分配 3、 位段的跨平台问题 C语言内置类型:char、short、

c语言——自定义类型之结构体_轻轻敲醒沉睡的心灵d(ŐдŐ๑)的博客-爱代码爱编程

目录 一、结构体定义(声明) 二、结构体类型的变量 三、特殊结构体 四、结构体的嵌套定义 五、结构体变量的定义和初始化 六、结构体的内存对齐 1.内存对齐是什么 2.内存对齐的规则 3.为什么有内存对齐(意义)  七、结构体传参 1.一个栗子 2.传值 3.传址 3.总结 八、位段 1.位段的声明 2.位段的内存分配 3

自定义类型-结构体-爱代码爱编程

1.结构体的声明 1.1结构体的基础知识 结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。 1.2结构的声明 struct tag { member-list; }varia

golang排序自定义类型(结构体)-爱代码爱编程

golang排序自定义类型 我们需要用到go自带的标准库标sort包 sort包提供了排序切片和用户自定义数据集以及相关功能的函数 sort包主要针对[]int、[]float64、[]string,以及其他自定义切片

c语言自定义类型之结构体详解-爱代码爱编程

前言      初识C语言的码友们一定学过C语言中的基本数据类型,比如我们常见的整型,浮点型,字符型等等基本数据类型,但是对人或物这一类复杂对象的数据要如何进行存储呢?这个知识点就涉及到了本篇博客所主要讲解的用来存储复杂对象的结构体类型。 目录 1.结构体声明及结构体变量定义 2.结构体自引用 3.结构体大小计算(内存对齐->对默认对齐数进

c语言——自定义类型之结构体_结构体重定义-爱代码爱编程

目录 🎄 前言 🎄结构体的类型,使用结构体和结构体内存分配 🍇1.结构体的声明 🍇2.特殊的结构体声明 🍇3.结构体的自引用 🍇4.结构体类型名重定义  ⭐️那么我们怎么去重定义结构体类型呢?  ⭐️带有嵌套的结构体重定义 🍇5.结构体变量的定义和初始化  ⭐️结构体逐语句初始化 🍇6.结构体的输出 🍇7.结构体占用内存大小

【c语言】自定义类型—结构体_c语言在结构体末尾加单词是什么意思-爱代码爱编程

目录 1 结构体类型的声明 1.1 结构的声明 1.2 匿名结构的声明 2 结构体的自引用 3 结构体变量的定义与初始化 4 结构体内存对齐与大小计算 4.1 结构体的内存对齐规则 4.2 存在内存对齐的原因 4.3 默认对齐数的修改 5 结构体传参         说起C语言中的类型,我们可能都会想到char\shor

【c语言进阶】自定义类型之结构体_c语言 数据结构stu4未定义-爱代码爱编程

目录 一:结构体1.1:结构的基础知识: 1.2:结构的声明: 1.3:特殊声明(匿名结构体): 1.4:结构的自引用: 1.5:结构体变量的定义和初始化: 1.6:结构体的内存对其:1.6.1:为

c语言中的自定义类型之结构体_封装偏移量为0-爱代码爱编程

目录: 1.结构体基础知识2.结构体的声明3.结构体的不完全声明4.结构体变量的定义和初始化5.结构体的内存对齐6.结构体的自引用 1.结构体基础知识 结构体是一些值的集合,这些值成为成员变量。结构