结构体,联合体,枚举详解

目录

  1. 结构体
  2. 联合体
  3. 枚举常量

1.结构体

在C语言中,系统已经提供了一些数据类型,比如float,int,double,char等,但是我们有时会需要更复杂的类型来描述一个数据。假如我想描述一个学生,我需要知道他的学号,姓名,性别,那么我就需要三个类型来分别保存他的信息,到时候需要信息时还得分别查找,显然这是不方便的。因此有了结构体,我们可以根据自己所需来定义数据类型。

简言之,结构体是由不同的类型数据组成的组合型数据结构。

  • 结构体类型的声明以及定义

    struct 结构体名

    {

    成员列表;

    }结构体变量名;

    这就是结构体声明的一个基本形式,写个结构体给大家看看。

    struct students
    {char name [20];int xuehao[20];char xinbie[5];
    }a,b,c;
    

    struct students 为结构体名,这相当于,我们熟知的int ,char,float,就是类型的意思。

    { }括号里面的是成员列表,需要注意的是这是结构体声明,我们不可以在里面赋值,这从逻辑上就是错误的,我们想要赋值,只能给变量赋值,怎么能给类型赋值呢。

    然后是,a,b,c 这是结构体变量名,我们可以对它们进行赋值。

    还要提一嘴的是一种特殊的定义,就是不加结构体名。

    struct
    {char a[20];int b;
    }w,q;
    

    这样定义会导致一种情况,就是无法再继续定义其他结构体变量,就是说有且仅有w,q两个变量。

  • 结构体的初始化和引用

    结构体的初始化有两种方式,一种是再定义结构体时进行初始化,一种是建立结构体变量,在去初始化。

    struct students
    {char name [20];int xuehao[20];char xinbie[5];
    }a={"张三",12345667,"男"};
    int main()
    {struct students b={"李四",233244,"男"};return 0;
    }
    

    这两种方式都可以,唯一的区别在于,a是全局变量,b是临时变量。

    结构体的引用也有两种方式一种是直接引用,另一种是通过指针来引用。

    struct students
    {char name [20];int xuehao[20];char xinbie[5];
    }a={"张三",12345667,"男"};
    int main()
    {struct students b={"李四",233244,"男"};printf("%s %d %s",b.name,b.xuehao,b.xinbie);return 0;
    }
    

    这就是直接引用,通过 变量名.成员名 的方式来引用,. 这个点是解引用操作符。

    struct students
    {char name [20];int xuehao[20];char xinbie[5];
    }a={"张三",12345667,"男"};
    int main()
    {struct students b={"李四",233244,"男"};struct students *p=&b;printf("%s %d %s",p->name,p->xuehao,p->xinbie);return 0;
    }
    

    通过指针的形式也可以引用,只不过,需要换个操作符 ->。

  • 结构体内存对齐

    结构体的所占内存的大小取决于什么,我们如果不清楚结构体内存对齐,那么可能会直接将结构体的成员变量所占内存加起来。其实这是错误的。接下来我们就一步一步的解析。

    先上代码。

    #include<stdio.h>
    int main()
    {struct a{char b;//1字节int i;//4字节char c;//1字节};printf("%d ", sizeof(struct a));return 0;
    }
    

    大家可以想一波。

    运行结果如下:

    这就用到内存对齐的知识解决了。先说说内存对齐的规则:

    1. 第一个成员变量在与结构体偏移量为0的地址处。
    2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    3. 结构体总大小为最大对齐数的整数倍。
    4. 嵌套了结构体的情况,结构体的总大小就是包括嵌套结构体成员变量的最大对齐数的整数倍。

对齐数=编译器默认的一个对齐数于该成员大小的较小值。

vs环境下,对齐数的默认值为8。

linux中的默认值为4。

了解了规则,我们来说上题:

首先首成员变量b,放在起始位置(偏移量为0),接下来是i,int i是4个字节,和vs环境默认的对齐数8比较取得较小值,所以对齐数4,要放在偏移量为4的倍数上,所以往下走就到了偏移量为4的位置处。此处浪费了3个字节。char c的字节是1,对齐数也是1,所以直接放在int i变量下面。加起来就是9字节,根据规则总大小为最大对齐数的整数倍,所以就是12字节。

再来一道题,

#include<stdio.h>
int main()
{struct a{char b;//1字节char c;//1字节int i;//4字节};printf("%d ", sizeof(struct a));return 0;
}

结果是8。

加起来是6个字节,但是总大小为最大对齐数的整数倍,所以变成了8个字节。

我们也可以自己设置默认对齐数

#pragma pack(默认对齐数)//设置默认对齐数
#pragma pack()//取消默认对齐数
  • 结构体实现位段

    位段的声明与结构体的声明类似,但需要注意两点:

    1. 位段的成员必须是int,unsigned int或char
    2. 位段的成员名后边有一个冒号和一个数字
    3. 位段的空间开辟是按照需要以4个字节或1个字节的方式来开辟的
struct a
{int a:2;int b:5;int c:10;int d:30;
};


总共8个字节。解释一下 冒号加个数字 是啥意思,就是说那个整型只占冒号后数字个比特位,也就是只存取冒号后数字个比特位。

那么,我们可以写个代码画画图,来解释一下位段是如何存储以及开辟空间的。

#include<stdio.h>
int main()
{struct a{char a : 2;char b : 5;char c : 6;char d : 3;};//初始化一下位段struct a s = { 0 };s.a = 10;s.b = 12;s.c = 7;s.d = 15;return 0;
}

先文字描述一下,这个位段由四个char组成,a变量只占2bite,b变量占5bite,c变量占6bite,d变量占3bite。一个字节的方式来开辟,那么就是8个比特位的方式开辟。

根据这副图我们发现它是占了三个字节,并且在内存中储存的十六进制是32,07,07。我们调试一波看看结果。

发现确实如此,所以在vs下,位段的使用规则大致我们已经了解,我做一个概述,位段根据需要以1字节或者4字节来开辟内存,接着在开辟的空间里放数据,当一字节或4字节的空间不足以容纳下一个变量时,直接再开辟一个1字节或4字节的内存来容纳变量,依次类推。

vs环境下,我们已经知道位段的存储方式,但是,位段是不跨平台的,在其他平台存储方式是不确定的。

  • 结构体传参

    结构体的传参,可以传值(传结构体),也可以传址(传结构体的地址)。函数传参是要压栈的,这就会占用内存,所以一般都用传址的方式进行结构体传参。函数压栈我之前的博客里有写,这里不做过多赘述。

    #include<stdio.h>struct a
    {int a;int b;
    };void print1(struct a s){printf("%d %d\n", s.a, s.b);}void print2(struct a* p){printf("%d %d\n", p->a, p->b);}
    int main()
    {struct a s = { 4, 3 };print1(s);//传值调用print2(&s);//传址调用return 0;
    }
    

2.联合体

联合体又称为共用体,意思就是几个变量共用一处地址。

  • 联合体的声明以及定义

    union 联合体名

    {

    成员列表;

    }变量列表;

    这是联合体的基本形式,和结构体基本一致。定义变量也和结构体一样,可以在声明时的变量列表处定义 变量,也可以用union 联合体名 变量名 定义临时变量。

union a
{char g;int h;
}b,c,d;//全局变量
int main()
{union a w;//局部变量
}
  • 联合体的特点

    1. 联合体的大小为最大成员变量的整数倍。

    2. 联合体相当于同一个地址,被多个变量共用,整型,浮点型等变量,在内存中都是二进制01010110组成的,关键在于他的读取方式不同。到底要把它看成浮点型,还是整型就看你如何使用它了。

union a
{float g;int h;
}b;
int main()
{b.g=1.0;printf("%f\n",b.g);printf("%d ",b.h);return 0;
}


这是代码的运行结果,你将这段二进制看出浮点型和整型取决于你的使用。

  1. 联合体变量赋值时,最后一次赋值为最终赋值,之前的赋值都被覆盖了。还有只能给一个成员变量赋值,不能多个同时赋值。

    union a
    {float h;char j;int k;
    }b;
    b={1.0,'a',4};//错误
    b=1;//正确b.h=4;
    b.j=3;
    b.k=2;
    //最终留下的是最后赋值的2
    

3,枚举常量

枚举常量就是将一些(不看作常量)字符定义成常量。我们知道#define a 3,就是将a定义成立了常量3。枚举的出现使定义常量变得方便,一下可以定义一堆,而且也方便调试。

  • 枚举的定义

    enum 枚举名

    {

    成员列表,(用逗号隔开)

    }变量列表;

  • 枚举的特点

    枚举常量就是{ }括号里的内容,系统会默认从枚举常量的大小从0依次加1,我们也可以给成员赋值,没赋值的就比前一个大1。

enum day
{mon,//0tus,//1wed,//2thur,//3fri,//4sat,//5sun,//6
};
enum a
{h=5,i,//6j=10,k=18,l;//19
}

以上就是本期内容,希望大家可以有所收获。

结构体,联合体,枚举详解相关推荐

  1. C语言结构体与指针ppt,c语言指针和结构体:链表详解.ppt

    c语言指针和结构体:链表详解.ppt 1,第十一章 链表,2,例跳马.依下图将每一步跳马之后的位置x,y放到一个"结点"里,再用"链子穿起来",形成一条链,相邻 ...

  2. go结构体初始化_go嵌套匿名结构体的初始化详解

    go匿名结构体 嵌套匿名结构体的 示例代码片. type debugConfig struct { MaxQueueDepth int `json:"maxQueueDepth"` ...

  3. c语言结构体成员变量私有化,C语言中结构体变量私有化详解

    C语言中结构体变量私有化详解 背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚 ...

  4. C++中的结构体vector排序详解

    C++中的结构体vector排序详解 使用sort函数对一个vector很常用,前提是通文件中必须包含#include ,但是针对结构体vector排序则需要进行一定的改动.具体事例如下所示: // ...

  5. c语言结构体联合体与枚举考点,C语言-结构体+联合体+枚举

    #include #include #include //1.结构体:是一种构造数据类型 //结构体的用途:把不同的数据类型整合起来,成为一个自定义的数据类型 //1.1 定义一个结构体(定义结构体的 ...

  6. c || 结构体 联合体 枚举类型 字符串

    文章目录 结构体struct :类型设计 结构体赋值 结构体类型指针 结构体的内存对齐 基本数据类型字节数 指定对齐值 联合体union 枚举:把需要的取值一一列举 枚举与#define的区别 字符串 ...

  7. C/C++结构体字节对齐详解

    结构体的sizeof 先看一个结构体: struct S1 {     char c;     int i; }; sizeof(S1)在VC6中按默认设置得到的结果为8. 我们先看看sizeof的定 ...

  8. Linux C Socket编程发送结构体、文件详解及实例

    利用Socket发送文件.结构体.数字等,是在Socket编程中经常需要用到的.由于Socket只能发送字符串,所以可以使用发送字符串的方式发送文件.结构体.数字等等. 本文:http://www.c ...

  9. c语言实现结构体变量private,C语言中结构体变量私有化详解

    背景介绍 操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 什么是结构体? 在C语言中,结构体(struct)指的是一种数据结构,是C语言中聚合数据类型(aggregate ...

  10. 32.【C/C++ 结构体全类型 (详解)】

    C结构体的应用 (一).什么是结构体? (二).结构体的声明: 2.1介绍一下上面的结构体声明: 2.2struct声明的位置 2.3标记名的可省略性 (三).结构体变量的定义 3.1分配空间 3.2 ...

最新文章

  1. nova ERROR (ClientException): 解决方法
  2. aggr代码 cellranger_单细胞转录组测序数据分析流程-数据预处理
  3. 华硕笔记本自带win10改win7的方法
  4. Python入门100题 | 第039题
  5. 10分钟理解依赖注入
  6. 40种网站设计常用方法
  7. Jsp传值方式(乱码问题的解决)
  8. 轻量级的 JavaScript 弹出框脚本:TinyBox
  9. mysql myisam表加索引_MyISAM和InnoDB的索引实现
  10. 调试Python的方式
  11. 用echarts绘制饼图---绘制南丁格尔玫瑰图
  12. linux怎么做ppapi工具,如何在Linux上构建PPAPI插件?
  13. 由置换反应引发的思考
  14. ADODB.Recordset 错误 #x27;800a0bb9#x27; 参数类型不正确,或不在可以接受的范围之内,或与其他参数冲突。
  15. 从RTP包中分析OPUS码流
  16. 文本处理命令 cat more less cut wc sort uniq
  17. SpeechSynthesisUtterance文字转语音播报
  18. Office Word 不显示 Citavi 插件,如何修复?
  19. 洛谷 P1460 健康的荷斯坦奶牛 Healthy Holsteins
  20. wo de wen jian

热门文章

  1. Oracle密码过期,取消密码180天限制
  2. Linux MySQL下载安装
  3. 接口文档要写在概要设计里吗_方法论:产品经理写好一份需求的系统化思考模型...
  4. How to Read an Academic Article-如何阅读学术文章
  5. 哈尔滨工业大学 2023年春人工智能数学基础期末真题
  6. 对话同盾科技李晓林:知识联邦生态系统或成为AI3.0时代的重要基石
  7. 苹果和安卓手机的计算器,为什么1÷3×3的结果不等于1?
  8. 提高水泵可靠度与生产效率:故障诊断系统实践解析
  9. Less中的混入用法(类似于函数)
  10. 小程序tabBar图标显示过大处理