首页 > 其他分享 >C语言----自定义类型:联合和枚举

C语言----自定义类型:联合和枚举

时间:2024-06-20 11:00:20浏览次数:18  
标签:char 自定义 int 联合体 C语言 ---- union 枚举 printf

 



1.联合体

联合体的特点

像结构体一样,联合体也是一个或者多个成员构成的,这些成员可以是不同的类型

联合体的关键字:union

结构体的关键字:struct

枚举的关键字:enum

但是编译器只为最⼤的成员分配⾜够的内存空间。联合体的特点是所有成员共⽤同⼀块内存空间。所

以联合体也叫:共⽤体。

//struct S
//{
//    char c;
//    int i;
//
//};
//union Un
//{
//    char c;
//    int i;
//};
//int main()
//{
//    printf("%zd\n", sizeof(struct S));//8
//    printf("%zd\n", sizeof(union Un));//4
//
//    return 0;
//}
/*
但是编译器只为最⼤的成员分配⾜够的内存空间。
联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体。

联合体的特点是所有成员共⽤同⼀块内存空间,这样一个联合变量的大小,至少是最大成员的大小
(因为联合至少的有能力保存最大的那个成员)

那么为什么这里是4呢?

*/


//union Un
//{
//    char c;
//    int i;
//};
//int main()
//{
//    union Un un = { 0 };
//    printf("%zd\n", sizeof(union Un));
//    printf("%p\n", &un);//007EFDD4
把un里面的c和i的地址都打印出来
//    printf("%p\n", &(un.c));//007EFDD4
//    printf("%p\n", &(un.i));//007EFDD4
//    return 0;
//}
/*
取出的地址都是相同的
第一个字节是c,所有的4个字节都是i
所以我们发现i和c公用这4个字节的空间
所以联合体也叫共用体

我们可以发现,当我们用i的时候我们就不能用c
用c的时候就不能用i
因为改i的时候,c也改了

所以联合体成员在使用的时候,一次只能用一个成员,不能同时一起用

同一个时间只能用一个成员




对于结构体的话,c和i有各自的空间,但是对于联合体来说,成员共用空间
*/

union Un
{
    char c;
    int i;
};
int main()
{ 
    union Un un = { 0 };
    un.i = 0x11223344;
    un.c = 0x55;
    //经过调试我们不难发现随着c的改变,i也被改变了
    return 0;
}

联合体的特点是所有成员共⽤同⼀块内存空间。所以联合体也叫:共⽤体。

联合体大小的计算

联合的大小至少是最大成员的大小。

当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍

//union Un
//{
//    char arr[5];//对齐数是1
//    //这个数组放在这里,跟放5个char类型是一样的
//
//    int i;//对齐数是4
//};
//int main()
//{
//    printf("%d\n", sizeof(union Un));//8
//    return 0;
//}
/*
计算出的是8,所以我们得知联合体的大小不一定是最大成员的大小
联合体的大小至少是最大成员大大小


这个联合体最大对齐数是4
那么联合体的总大小一定要是4的倍数


这个联合体最大成员的大小是这个数组,大小是5,就是相当于5个char类型

但是5不是4的倍数,所以后面还要浪费3个字节,对齐8,所以最终的大小是8个字节


所以联合体也是存在内存空间的对齐的
*/


//练习计算联合体大小
union Un
{
    short arr[7];//对齐数是1
    //这个数组放在这里,跟放5个char类型是一样的

    int i;//对齐数是4
};
int main()
{
    printf("%d\n", sizeof(union Un));//16
    return 0;
}


/*
因为shourt类型是2个字节,那么7个short就是14个字节了

short arr的对齐数是按照2来算的

i的对齐数是4,那么最大对齐数是4
那么联合体的大小必须是4的倍数


虽然说联合体很节省空间,但是也不是那么很绝对的节省空间
*/

联合体的运用

/*
图书:库存量、价格、商品类型、书名、作者、⻚数
杯⼦:商品类型、价格、库存量设计、
衬衫:设计、可选颜⾊、可选尺⼨、库存量、价格、商品类型
*/

//struct gift_list
//{
//    //公共属性
//    int stock_number;//库存量
//    double price; //定价
//    int item_type;//商品类型
//
//    char title[20];//书名
//    char author[20];//作者
//    int num_pages;//⻚数
//
//    char design[30];//设计
//    int colors;//颜⾊
//    int sizes;//尺⼨
//};
//
/*
上述的结构其实设计的很简单,⽤起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样
使得结构体的⼤⼩就会偏⼤,⽐较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息
是常⽤的。⽐如:
商品是图书,就不需要design、colors、sizes。
所以我们就可以把公共属性单独写出来,剩余属于各种商品本⾝的属性使⽤联合体起来,这样就可以
介绍所需的内存空间,⼀定程度上节省了内存。
*/


struct gift_list
{
    int stock_number;//库存量
    double price; //定价
    int item_type;//商品类型

    union {
        struct
        {
            char title[20];//书名
            char author[20];//作者
            int num_pages;//⻚数
        }book;
        struct
        {
            char design[30];//设计
        }mug;
        struct
        {
            char design[30];//设计
            int colors;//颜⾊
            int sizes;//尺⼨
        }shirt;
    }item;
};

//将我们每次就只用一个的东西拎出来放到联合体里面

//我们只用开辟一块空间,就能将所有东西存进去
//每次只取一样东西
//我们这个union没有写名字,写成匿名,因为这些成员我们每次用的时候只用一次

联合体的练习

union Un
{
    char c;//第一个字节
    int i;
};
int main()
{
    union Un un = {0};
    un.i = 1;
    if (un.c == 1)
    {
        printf("小端\n");
    }
    else
    {
        printf("大端\n");
    }
    return 0;
}

2.枚举类型

枚举类型的声明

枚举顾名思义就是一一列举的意思

就是将可能的值一一列举出来

我们可以声明枚举类型

枚举的关键字是enum

//struct A
//{
//    int _a : 2;
//    int _b : 5;
//    int _c : 10;
//    int _d : 30;
//};
//int main()
//{
//    struct A sa = { 0 };
//    //scanf("%d", &sa._b);//这是错误的
//
//    //正确的⽰范
//    int b = 0;
//    scanf("%d", &b);
//    sa._b = b;//直接进行赋值
//    return 0;
//}

enum Day//星期
{
    Mon,
    Tues,
    Wed,
    Thur,
    Fri,
    Sat,
    Sun
};

enum Sex//姓名
{
    //该枚举类型的三种取值
    //都是常量,被称为枚举常量
    MALE=2,
    FEMALE=4,//我们这里是给常量一个初始值,到后面就无法进行更改了
    SECRET=8
};

int main()
{
    //我们给枚举变量赋值的都是它的可能取值
    /*enum Sex sex1 = MALE;
    enum Sex sex2 = FEMALE;*/
    printf("%d\n", MALE);//0
    printf("%d\n", FEMALE);//1
    printf("%d\n", SECRET);//2
    /*
    打印出来的值是0 1 2
    因为枚举常量的值默认是从0开始的,一次递增往下走,涨1
    */
    //如果我们希望这个值是我们期望的,我们可以在枚举类型中进行更改

    //假如我们仅仅只改变了第一个值为2
    //那么剩下两个值就是3 4


    //如果第1个值不赋值,第二个值赋值为8,那么打印出来的就是0 8 9
    //从我们设置的值进行递增,第一个值不设置的话默认就是0

    return 0;
}

枚举类型的优点

那么我们为什么使用枚举呢?

为什么使⽤枚举?

我们可以使⽤ #define 定义常量,为什么⾮要使⽤枚举?

枚举的优点:

  1. 增加代码的可读性和可维护性

  2. 和#define定义的标识符⽐较枚举有类型检查,更加严谨。

  3. 便于调试,预处理阶段会删除 #define 定义的符号

  4. 使⽤⽅便,⼀次可以定义多个常量

  5. 枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤

enum Sex//姓名
{

    MALE=2,
    FEMALE=4,
    SECRET=8
};

int main()
{
    enum Sex sex1 = MALE;//因为MALE的类型是enum Sex类型的,所以这么进行赋值是对的
    //enum Sex sex1 = 3;这么赋值就是错的,因为3的类型是整型,但是赋值的前面的枚举类型的
    //因为类型是不一样的,所以我们不能进行赋值
    return 0;
}

define定义的话是全局的定义的

枚举类型的使用

enum Color//颜⾊
 {
   RED=1,
   GREEN=2,
   BLUE=4
 };

 enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值
//写一个计算器---完成整数的加法、减法、乘法

enum Option
{
    EXIT,//默认的值是0
    ADD=1,//值表达的是1
    SUB,
    MULL,
    DIV

};
int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mull(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}
void menu()//菜单
{
    printf("**********************************\n");
    printf("**********1.  add   2.  sub*******\n");
    printf("**********3.  mull  4.  div*******\n");
    printf("********* 0.    exit    **********\n");
    printf("**********************************\n");
}
int main()
{
    int input = 0,ret=0;
    int x, y;
    do
    {
        menu();
        printf("请选择一个算法");
        scanf("%d", &input);
        switch (input)
        {
        case ADD://这么写的话,ADD的值还是表达的1
            printf("请输入两个数");
            scanf("%d %d", &x, &y);
            ret=Add(x,y);
            printf("%d\n", ret);
            break;
        case SUB://对于这种我们想写什么就写什么case ADD都是可以的:
            //我们是可以不用安排这个顺序的
            printf("请输入两个数");
            scanf("%d %d", &x, &y);
            ret = Sub(x, y);
            printf("%d\n", ret);
            break;
        case MULL: 
            printf("请输入两个数");
            scanf("%d %d", &x, &y);
            ret= Mull(x, y);
            printf("%d\n", ret);

            break;
        case DIV:
            printf("请输入两个数");
            scanf("%d %d", &x, &y);
            ret = Div(x, y);
            printf("%d\n", ret);

            break;
        case 0:
            printf("退出\n");
            break;
        default:
            printf("选择错误,重新选择\n");
            break;
        }
    } while (input);
    return 0;
}

标签:char,自定义,int,联合体,C语言,----,union,枚举,printf
From: https://blog.csdn.net/2301_80863610/article/details/139826218

相关文章

  • Android面试题 之App性能优化的卡顿监控和卡顿优化
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点卡顿优化这里主要介绍卡顿优化方面的布局优化布局优化1、在主线程中,加载SP,或者是缓存加载,JSON解析,可以放到Idelhander2、viewpager的懒加载,用viewpager2替换v......
  • 基于springboot实现宠物咖啡馆平台管理系统项目【项目源码+论文说明】计算机毕业设计
    摘要随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了基于SpringBoot的宠物咖啡馆平台的设计与实现的开发全过程。通过分析基于SpringBoot的宠物咖啡馆平台的设计与实现管理的不足,创建了一个计算机管理基于SpringBoot的......
  • 生成式人工智能不会为你建立工程团队
    生成式人工智能不会为你建立工程团队软件产业正在成长在某种程度上,这是行业成熟的必然结果。任何领域的早期都有点像狂野的西部,赌注很低,没有监管,标准刚刚形成。如果你看看其他行业的早期历史——医药、电影、广播——相似之处是惊人的。任何新兴技术都有一个神奇的时刻,......
  • World Map Globe Edition 2
    只需点击几下,WorldPoliticalMap-GlobeEdition2就会在场景添加一个美丽且交互式的3D世界地图。将地球预制件拖动到场景中并自定义外观。完整的资产,具有强大的可视化功能、示例和丰富的API,适用于构建VR、桌面和移动游戏和应用程序。主要功能:-在不访问互联网的情况下,按......
  • 【计算机网络仿真】b站湖科大教书匠思科Packet Tracer——实验2 MAC地址,IP地址,ARP协议
    一、实验目的1.掌握计算机网络的寻址问题;2.验证MAC地址与IP地址的关系;3.了解ARP协议的作用。二、实验要求1.使用CiscoPacketTracer仿真平台;2.观看B站湖科大教书匠仿真实验视频,完成对应实验。三、实验内容1.构建网络拓扑;2.配置网络设备;3.跟踪并查看数据包;4.在实......
  • 【YOLOv10改进[注意力]】使用迭代注意力特征融合(iterative attentional feature fusio
    本文将进行使用迭代注意力特征融合(iterativeattentionalfeaturefusion,iAFF)改进c2f ,助力YOLOv10目标检测效果的实践,文中含全部代码、详细修改方式以及手撕结构图。助您轻松理解改进的方法。改进前和改进后的参数对比: 目录一AttentionalFeatureFusion(2020)二使用......
  • django线上兼职平台系统 毕业设计-附源码83320
    摘 要信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对线上兼职等问题,对线上兼职进行研究分析,然后开发设计出django线上兼职平台系统以解决问题。......
  • Windows安全加固总结(非常详细)零基础入门到精通,收藏这一篇就够了
    为了达到安全的目的,一般来说我们需要关注操作系统的八个方面:补丁管理>账号漏洞>授权管理>服务管理>功能优化>文件管理>远程访问控制>日志审计其中:补丁管理使用最新版的补丁,避免使系统存在已知的漏洞,从而被攻击者利用。账号口令梳理出系统中正在使......
  • 使用Element-plus的消息组件(ElMessage或ElNotification)时,出现z-index异常,导致被遮挡
    Nuxt3中使用ElementPlus的消息组件(ElMessage或ElNotification)时,出现z-index异常,导致被遮挡。背景介绍:我的页面中已经弹出了两个el-drawer组件,此种情况下我需要弹出一个提示信息。无论我是使用ElMessage,还是使用ElNotification都存在相同的问题,就是"遮罩层"给遮挡住以下......
  • 【问题】Ubuntu下使用ftp命令下载文件
    Ubuntu下使用ftp命令下载文件具体的方法示例如下:$ ftp192.168.180.3Connectedto192.168.180.3.Name(192.168.180.3:test):此处输入用户名 Password:此处输入对应的密码/*查看当前路径*/ftp> pwd257"/"iscurrentdirectory. ftp>cdtest250CWDcommands......