目录
1. 联合体
1.1 联合体类型的声明
联合体和结构体一样,联合体也是由一个或多个成员构成,这些成员可以是不同的类型。
但是编译器只为最大的成员分配足够的内存空间。联合体的特点是所有成员共用同⼀块内存空间。所以联合体也叫:共用体。
#include <stdio.h>
struct S//结构体
{
char c;
int i;
};
union Un//联合体也可以有多个成员,而且每个成员可以是不同类型
{
char c;
int i;
};
int main()
{
printf("%d\n", sizeof(struct S));
printf("%d\n", sizeof(union Un));
return 0;
}
输出结构:
1.2 联合体的特点
联合的成员是共⽤同⼀块内存空间的,这样⼀个联合变量的大小,至少是最大成员的大小(因为联合 至少得有能力保存最大的那个成员)。
#include<stdio.h>
union Un
{
char c;
int i;
};
int main()
{
union Un un;
printf("%d\n", sizeof(un));//计算un变量的大小
printf("%p\n", &un);//取出un的地址
printf("%p\n", &(un.c));//取出联合体成员c的地址
printf("%p\n", &(un.i));//取出联合体成员i的地址
return 0;
}
输出结构:
解析:
修改i可以改变c或者修改c可以改变i,因为它们共用同一块地址。
内存布局:
1.3 相同成员的结构体和联合体对比
1.4 联合体大小的计算
联合的大小至少是最大成员的大小。
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。
#include <stdio.h>
union Un1
{
char c[5];
int i;
};
union Un2
{
short c[7];
int i;
};
int main()
{
printf("%d\n", sizeof(union Un1));
printf("%d\n", sizeof(union Un2));
return 0;
}
输出结果:
解析:
联合体在一定程度上可以节省空间,但也不是绝对的节省。
使⽤联合体是可以节省空间的,举例: 比如,我们要搞⼀个活动,要上线⼀个礼品兑换单,礼品兑换单中有三种商品:图书,杯子,衬衫。 每⼀种商品都有:库存量,价格,商品类型和商品类型相关的其他信息。
图书:书名,作者,页数
杯子:设计
衬衫:设计,可选颜色,可选尺寸
上述的结构其实设计的很简单,用起来也⽅便,但是结构的设计中包含了所有礼品的各种属性,这样使得结构体的大小就会偏大,比较浪费内存。因为对于礼品兑换单中的商品来说,只有部分属性信息 是常⽤的。比如:
商品是图书,就不需要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;
};
1.5 联合的⼀个练习
#include <stdio.h>
int check_sys()
{
union
{
int i;
char c;
}un;
un.i = 1;
return un.c;//返回1是⼩端,返回0是⼤端
}
int main()
{
if (check_sys())
{
printf("小端\n");
}
else
{
printf("大端\n");
}
}
2. 枚举类型
2.1 枚举类型的声明
枚举顾名思义就是⼀⼀列举。
把可能的取值⼀⼀列举。
就比如生活中的星期,星期一到星期七是有限的七天,可以一一列举,月份有12个月,也可以一一列举。
//enum是枚举关键字
//Day是枚举类型的名字
enum Day//星期
{
//该枚举类型的七种可能取值
//它们都是常量,被称为枚举常量
Mon,
Tues,
Wed,
Thur,
Fri,
Sat,
Sun
};
enum Sex//性别
{
MALE,
FEMALE,
SECRET
};
enum Color//颜⾊
{
RED,
GREEN,
BLUE
};
以上定义的 enum Day, enum Sex,enum Color都是枚举类型。{}中的内容是枚举类型的可能取值,也叫枚举常量 。
用法:
enum Sex//性别
{
MALE,//男
FEMALE,//女
SECRET//保密
};
int main()
{
enum Sex sex1 = MALE;//创建枚举变量,并且赋值为MALE,赋值赋的是可能取值
enum Sex sex2 = FEMALE;
return 0;
}
创建枚举变量,赋值赋的是可能取值,那么它们的可能取值有什么特点呢?
都说常量是不可以修改的,那为什么枚举中可以修改呢?
我们在枚举中定义数值是初始化,不是修改,但是要是在别的地方给枚举中的常量重新赋值,编译器是不允许的,会报错。
2.2 枚举类型的优点
为什么使用枚举?
我们可以使用#define定义常量,为什么非要使用枚举?
1. 增加代码的可读性和可维护性 ,上述的代码FEMALE表示的值就是5,但是如果单单写成的话就只是个数字,没有任何的意义,可读性不高。
2. 和#define定义的标识符比较枚举有类型检查,更加严谨。
3. 便于调试,预处理阶段会删除#define 定义的符号
4. 使用方便,⼀次可以定义多个常量
5. 枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用
2.3 枚举类型的使用
enum Sex
{
MALE,
FEMALE,
SECRET
};
enum Sex sex = MALE;//使⽤枚举常量给枚举变量赋值
那是否可以拿整数给枚举变量赋值呢?在C语⾔中是可以的,但是在C++是不⾏的,C++的类型检查⽐ 较严格。
下面举个例子,可以让我们从这个例子中感受到枚举真正的好处。
写一个计算器,完成整数的加减乘除。
//记得包含头文件
int Add(int x, int y) { return x + y; }
int Sub(int x, int y) { return x - y; }
int Mul(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. mul 4. div************\n");
printf("************0. exit ************\n");
printf("*************************************\n");
}
enum Option
{
EXIT,//0
ADD,//1
SUB,//2
MUL,//3
DIV//4
};
int main()
{
int input = 0;
do
{
menu();
printf("请输入选项:\n");
scanf("%d", &input);
switch (input)
{
case ADD:
//Add函数传参,接收返回值,打印
break;
case SUB:
//.............
break;
case MUL:
//.............
break;
case DIV:
//.............
break;
case EXIT:
printf("退出计算器!!!\n");
break;
default:
printf("输入错误,请重新输入!!!\n");
break;
}
} while (input);
return 0;
}