关于结构体,枚举,联合的一些知识

首先我们来看一下什么是结构体

通俗来说,结构体便是各种类型的集合。

接下来便是各处所代表的含义了

例如,我们现在来描述一个人。

其中name,age,sex,addr,phone都是描述一个人的元素。记得不要忘记最后的分号噢

但其实,结构体声明的时候也可以省去标签,直接用struct进行声明,这种类型叫做匿名结构体类型。

请看下图:>

像这种直接省去标签的结构体类型比较特殊,但其中也有注意的点。

  1. 匿名结构体类型在创建变量的时候只能在这个位置创建:

2.请看以下代码:>

struct
{int i;char a;double c;
}a;struct
{int i;char a;double c;
}*p;int main()
{p = &a;return 0;
}

我们看到,这两个匿名结构体的成员变量是一模一样的,我们以此创建了一个变量a,和一个指针p,如果我们想要用p来存放a变量的地址的话,用p = &a,其实是非法的,我们编译这个代码后,编译器会报一个警告:

因此我们要避免出现上述代码的情况。

我们在学习函数时,曾经介绍过函数可以自己调用自己,也即函数的递归,那么结构体是否也能自己调用自己呢?,这就是我们要介绍的,结构体的自引用

结构体的自引用

首先请看以下代码:>

struct stu
{int age;char name[20];struct stu s;
};

像以上这种在结构体成员中包含自己类型的变量,可不可行呢?,如果可行的话,请说出以下代码的结果:>

struct stu
{int age;char name[20];struct stu s;
};int main()
{printf("%d\n", sizeof(struct stu));return 0;
}

是否已经感觉到不对劲了呢? 如果这段代码能跑起来的话,结果也应该为无穷大。

我们在vs环境中编译这段代码的话,你也会发现是跑不过去的。

正确的结构体自引用如下代码所示:>

struct stu
{int age;char name[20];struct stu*s;
};int main()
{printf("%d\n", sizeof(struct stu));return 0;
}

即在结构体成员中定义一个自己类型的结构体指针,我们让程序跑起来的话,结果为:>

(此处结构体大小的计算我们将会在后文介绍到)

结构体与typedef的一些联名

typedef为类型重命名的关键字,它同样适用于对结构体类型的重命名,以此来帮助我们更好的将代码简洁,明亮。

首先我们来看一下其基本模板:>

上图中,我们已经把struct student类型重命名为stu,因此,可以这样创建一个结构体变量

typedef struct student
{int age;
}stu;int main()
{stu s2 = { 0 };return 0;
}

在上面的代码中,我们用stu成功定义了一个结构体变量s2.

但是!在这个时候可能有些同学会说,那可不可以把代码写成这样呢?

即在结构体成员中率先使用stu创建一个变量s1,我们编译一下程序,会得到以下结果:>

编译器会报错。

那是因为,重命名的stu是在下图的方式开始起作用的:>

因此,编译器也就不认识stu这个标识符了。

结构体的定义和初始化

既然我们已经基本认识了结构体,接下来请观看结构体是如何定义和初始化的

最基本的两种方式如下所示:>

struct stu
{int age;char name[20];
}s1;int main()
{struct stu s2;return 0;
}

在这里我们定义了两个变量,一个是s1,一个是s2,它们分别的区别为:>

此外,在定义结构体变量的同时还可以对其初始化:

这里初始化的方式就和数组有点类似了,即用一个大括号来对其初始化。

有时候我们会遇到这种情况,即在结构体成员中又有另外一个结构体,那么我们应该如何初始化呢,请看下图

那我们在初始化时,只需要在大括号中再套一个大括号即可,即:>

里头的大括号完成的是对s1的初始化。

接下来便是有点小重要的部分,那便是结构体的内存对齐

结构体内存对齐

首先我们来看一下以下这段代码

struct test
{char a;int age;char b;
};int main()
{printf("%d\n", sizeof(struct test));return 0;
}

我曾经也认为这个结果时6个字节,但是,程序运行起来之后,得到的结果为:>

这是因为存在内存对齐现象,以下图将是对该代码的讲解:>

这里我们来了解一下对齐数应该如何计算。

举例:>

同理,变量age 和 b变量的对齐数为4, 1;请看下图

这样的话,我们就能将刚才的age和b变量放置在内存中了

黄色的区域就是age变量所占的区域,因为其对齐数为4,所以其要对齐到4的倍数处的地址处。1处便是b变量所占的区域,毕竟1是任何数字的倍数嘛。

此时,结构体所占的字节大小为:>

这个时候就有同学说了,此时结构体大小所占的内存空间不是9吗,实则不然,这里我们引出第三条规则:>

这里又引申出了最大对齐数的概念,大伙还记得我们在上面所算的对齐数吗,

最大对齐数即这些对齐数中最大的那个数,因此,在此处,最大对齐数为4, 结构体的总大小为4的倍数,因此,请看下图

这样的话,结构体的总大小就为12了,划×的部分是内存对齐而浪费掉的内存。

再来看下面这个例子

struct test1
{char a;int age;char b;
};struct test2
{char c;struct test1 s1;char d;double e;
};int main()
{printf("%d\n", sizeof(struct test2));return 0;
}

在一个结构体变量有其他结构体变量成员时,该如何计算呢,这里的话, 我们引申出第四条规则:>

同样的,我们来计算test2的大小。

首先,便是第一个成员防止在0偏移处的位置。

其次,第二个成员因为为结构体成员,因此,其对齐到其最大对齐数的整数倍处,又因为上面计算出了其最大对齐数为4,因此从偏移处为4的地方开始:>

其占用的内存空间为12个字节,这里我们上面已经计算过。

再然后,就是成员d了,成员d的对齐数为1,因此其对齐到16偏移处即可:

再接来就是最后一个成员变量e,其自身大小为8字节,vs默认编译器为8字节,因此其对齐数为8字节,其对齐到8字节的整数倍处:

粉色部分就是成员变量e所占的空间。

接下来是计算结构体类型的总大小,因为该结构体包含一个结构体变量,因此,其对齐到所有最大对齐数的整数倍,

因此,所有的最大对齐数最大为8,结构体的总大小要对齐到8的倍数的偏移处。

此处刚刚好占用内存空间为32,为8的整数倍,因此,结果为32,我们让程序运行起来,结果为:>

修改默认对齐数

我们可以通过 #pragma pack() 预处理指令来修改默认对齐数。

例如

#pragma pack(4) // 修改默认对齐数为4struct test1
{char a;int age;char b;
};#pragma pack() // 取消我们所设置的默认对齐数,还原为默认

位段

既然已经讲完了结构体,那就不得不谈一下结构体实现位段的能力

首先我们先来见识一下位段:>

struct A
{int a : 4;int b : 2;int c : 4;
};

那么A就是一个位段类型,要注意的是,位段的成员的类型只能是int、unsigned int或signed int。

请看下面以下这段代码,该代码运行的结果是什么?


struct A
{int a : 2;int b : 5;int c : 10;int d : 30;
};int main()
{printf("%d\n", sizeof(struct A));return 0;
}

我们让程序运行起来,得到的结果将会是:>

那么是如何计算的呢,请看下图:>

其次便是使用位段要注意的点:>

1.位段的成员可以是int unsigned int signed int 或者是char (属于整形家族)类型
2.位段的空间上是按照需要以4个字节( int)或者1个字节( char)的方式来开辟的。
3.位段涉及很多不确定因素,位段是不跨平台的, 注重可移植的程序应该避免使用位段。

枚举

枚举,按照字面意思来说,就是一一列举,把所有可能的值一一列出来

例如我们的一周:>

enum day
{MONDAY,TUESDAY,WENSDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY
};

又如我们的性别:>

enum sex
{MALE,FEMALE,SECRET
};

上述的定义的两种枚举类型day, 和sex 中的可能取值都是有值的,让我们来看看它的值为多少


也即:>

也即说明了这些可能取值是有值的,并且从0开始。

当然,我们在定义的时候也能给它赋初值,例如:>

enum Color//颜色
{RED,GREEN = 7,BLUE
};

这样的话,RED的值依然为0,但GREEN的值变为7,BLUE的值为8。

接下来便是枚举的使用了。例如:>

enum Color//颜色
{RED,GREEN = 7,BLUE
};int main()
{enum Color s1 = BLUE;return 0;
}

同时,还有其他用途,本人最常用的是用在这种情况

即在这种有菜单的情况下,通过枚举能够更加让读者更加清楚的了解代码.

联合的相关知识

联合是一种特殊的自定义类型,这种类型定义的变量包含一系列成员,但是这些成员共用一块空间,因此联合体也被称为共用体。

接下来请看以下代码:>

union un
{char a;int b;
};

这便是联合体最基本的样子了。

接下来,我们观看一段代码:>

union un
{char a;int b;
};int main()
{printf("%d\n", sizeof(union un));return 0;
}

它的结果是什么呢?,答案是4

要知道,联合体是共用一块内存块的,因此,联合体大小最小也是成员变量中最大的那个数。在此处,b变量为4个字节,因此总体的大小为4个字节。

但是为什么要强调最小呢? 因为联合体也存在对齐的情况,即当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

请看下面这段代码:>

union un
{char a[5];int b;
};int main()
{printf("%d\n", sizeof(union un));return 0;
}

这一段代码的结果是8,那是因为:>

关于结构体,枚举,联合的一些知识相关推荐

  1. 【C语言】自定义类型 结构体 枚举 联合

    结构体的基础知识 结构体是一些值的集合,这些值称为成员变量.结构体的每个成员可以是不同类型的变量. 结构体的声明 定义一个学生的结构体 struct Stu {char name[20];//名字in ...

  2. 【结构体——枚举——联合】

    文章目录 前言 结构体 结构体类型的声明 结构的自引用 结构体变量的定义和初始化 结构体内存对齐 修改默认对齐数 结构体传参 结构体实现位段(位段的填充&可移植性) 枚举 枚举类型的定义 枚举 ...

  3. 结构体枚举联合详解(附例题解析)

    目录: 结构体的初始化 结构体的内存对齐 位段 -->位段的内存分配 -->位段的跨平台问题 枚举的优点 联合的特点 联合体的大小计算 结构体的初始化 struct Stu {char n ...

  4. C语言 | 【耗费一夜总结三本C语言系列】之 结构体、联合、枚举

    前言 本章内容总结了结构体.联合.枚举,对于结构体总结了结构体指针用法,参数传递,内存对齐等较为重要的知识点. C语言 | 快速了解C的发展史

  5. 结构体+枚举+联合体

    结构体+枚举+联合体 结构体 结构体的声明 结构体的嵌套+链表 结构体变量的初始化 结构体的内存对齐 一.首先得掌握结构体的对齐规则 二.一些具体的例子 为什么存在内存对齐? 位段 位段的内存保存 枚 ...

  6. 结构体是纸老虎,旧知识新用法,easy

    结构体是纸老虎,旧知识新用法 先看一段程序: void func(int data) {printf("函数:data = %d\n",data);}int main() {int ...

  7. 7.3结构体是纸老虎,旧知识新用法

    7.3结构体是纸老虎,旧知识新用法 普通定义和结构体定义的不同方式和区别 #include<stdio.h> #include<stdlib.h> #include <s ...

  8. 【自定义类型】结构体,联合,枚举

    在我们学习C语言的时候,有几个自定义类型需要我们掌握,那么我也是根据自己的学习来分享一下自己的理解.希望与大家互相学习,共同进步! 文章目录 一:结构体 1.1:结构体的基础知识 1.2:结构的声明 ...

  9. C语言基本语法——结构体、联合和枚举

    一.结构体 1.什么是结构体 2.结构体语法格式 3.结构体所占内存空间 4.结构体成员赋值 二.联合 1.什么是联合 2.联合语法格式 三.枚举 1.什么是枚举 2.枚举语法格式 一.结构体 1.什 ...

  10. ios 结构体跟枚举变量的区别_IOS结构体、联合、枚举

    2.结构体 2.1是程序员自己创建的一种数据类型 2.2语法 2.2.1结构体的创建 2.2.2 使用结构体类型定义变量 2.2.3结构体变量的操作 2.2.3.1初始化:整体进行 2.2.3.2赋值 ...

最新文章

  1. 当前路径_[JSP] 07 JSP 路径问题
  2. link 和@import 的区别?
  3. 百度面试题:生产者 消费者问题
  4. 计算机技术停滞,究竟什么原因让科技停滞不前呢?
  5. android 第三方登录界面,Android App集成第三方登录与换肤指南
  6. Angular 界面元素的条件渲染
  7. 【NOIP模拟】健美猫
  8. 9.特殊权限 软连接 硬链接
  9. 禅道外部消息提示_Spring Boot中文参考指南(2.1.6)34、消息传递
  10. rocketmq 两个线程同时消费一个消息
  11. 鼠标滑轮滚动到相应位置,对应位置的div触发一些效果实现方式
  12. JAR 文件规范详解
  13. 。三十功名尘与土,八千里路云和月。莫等闲,白了少年头,空悲切
  14. 根据IP地址查询所在地
  15. 蒟蒻信安笔记4:CTF实践
  16. 傅里叶变换性质和常见信号的傅里叶变换
  17. 梦幻西游手游转区没服务器显示不出来,《梦幻西游手游》怎么转服 转服需要满足条件介绍...
  18. 中信银行总行信息科技岗(成都)2020届校招/秋招面经+薪资待遇(更新完,已offer)
  19. matlab错误dparsfa,Dpabi安装出错,求助大大佬
  20. win10 C盘突然少了许多空间解决办法

热门文章

  1. android手机是vivo吗,为什么最流畅的安卓手机竟然是VIVO和OPPO?
  2. linux 重定向 2 gt gt,Linux命令- echo、grep 、重定向、1gt;amp;2、2gt;amp;1的介绍
  3. linux 系统下关闭屏幕
  4. 使用react-split-pane简单记录
  5. 利用计算机程序快速得到9*9大小数独的解法
  6. Evision显示器无法设置1440*900分辨率的问题解决
  7. 基础阶段(三)MDP核心——贝尔曼方程
  8. 【最优化算法】基于【MATLAB】的最速下降仿真
  9. macbook蓝牙pan未连接_蓝牙自动重连机制
  10. 将图片转化成SVG格式(亲测可行)