阅读量: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 定义常量,为什么⾮要使⽤枚举?
枚举的优点:
增加代码的可读性和可维护性
和#define定义的标识符⽐较枚举有类型检查,更加严谨。
便于调试,预处理阶段会删除 #define 定义的符号
使⽤⽅便,⼀次可以定义多个常量
枚举常量是遵循作⽤域规则的,枚举声明在函数内,只能在函数内使⽤
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; }