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

avatar
作者
筋斗云
阅读量:0

 



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; } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!