C语言-自定义类型:联合和枚举
1.枚举
1.1枚举类型的声明
枚举顾名思义就是一一列举
把可能的值一一列举出来
例如:一周的星期,性别,月份等等
枚举的关键字:enum
enum day
{
mon,
tues,
wed,
thur,
fri,
sat,
sun,
};
enum sex
{
male,
female,
secret
};
上述是关于星期和性别的枚举声明定义
{}中的内从是枚举类型的可能取值,也叫做枚举常量
枚举常量的默认值是从0开始依次递增
所以fri和male的值是4和0
而且枚举常量的默认值是可以修改的,但是只能在定义中进行默认值的初始化,在main中也不能修改
图中可得在定义中对wed的默认值进行了修改,改成了5,所以fri的值就从5开始依次加1变成了7,而tues还是从0开始加1,所以是1
2.2枚举类型的优点
其实我们可以使用#define定义常量,为什么非要用枚举?
1.增加代码的可读性和可维护性
2.和#define定义的标识符比较枚举有类型检查,更加严谨(例如C++中就会出现问题)
3.便于调试,预处理阶段会删除#define定义的符号
4.使用方便,一次可以定义多个常量
5.枚举常量是遵循作用域规则的,枚举声明在函数内,只能在函数内使用
2.3枚举类型的使用
enum Color//颜⾊
{
RED = 1,
GREEN = 2,
BLUE = 4
};
enum Color clr = GREEN;//使⽤枚举常量给枚举变量赋值
是否可以拿整数给枚举变量赋值呢?在C语言中可以,但是C++中不行,C++的类型检查严格。
枚举使用的例子(计算加减乘除的计算器):
//枚举应用的例子
//计算器(加减乘除)
void menu()
{
printf("**请输入选择**\n");
printf("** 1. add **\n");
printf("** 2. sub **\n");
printf("** 3. mul **\n");
printf("** 4. div **\n");
printf("** 0. exit **\n");
}
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 0:
printf("退出\n");
break;
default:
printf("输入错误,请看选项重新选择\n");
break;
}
} while (input);
return 0;
}
这是之前我们写的(简洁版,只有框架,没有内容)
这里的1,2,3,4,0的数字是因为我们之前在menu里说明这些数字代表什么,所以才知道它们分别代表着加法减法等等
为了使得数据的可读性更清晰,我们便可以用枚举
//枚举应用的例子
//计算器(加减乘除)
enum jisuanqi
{
exit,//0
add,//1
sub,//2
mul,//3
div//4
};
void menu()
{
printf("**请输入选择**\n");
printf("** 1. add **\n");
printf("** 2. sub **\n");
printf("** 3. mul **\n");
printf("** 4. div **\n");
printf("** 0. exit **\n");
}
int main()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case add:
break;
case sub:
break;
case mul:
break;
case div:
break;
case exit:
printf("退出\n");
break;
default:
printf("输入错误,请看选项重新选择\n");
break;
}
} while (input);
return 0;
}
加上了枚举,每个case代表什么我们也就一目了然了,也不需要看menu来查找每个数字的含义。
2.联合体
2.1联合体的声明
和结构体相似,联合体也是一个或者多个成员构成,这些成员也可以是不同的类型
但是编译器只为联合体的最大的成员分配足够大的内存空间。联合体的特点是所有成员共有同一个内存空间,所以也叫做共用体
给联合体其中一个成员赋值,其他成员的值也跟着变化
//联合体的声明
union S
{
char a;
int n;
};
2.2联合体的特点
联合体的成员是共用同一块内存空间。所以一个联合变量的大小,至少是最大成员的大小
上图可知变量的大小是最大变量类型int的大小,成员的内存空间是同一个位置
2.3对比结构体和联合体
struct S
{
char c;
int i;
};
struct S s = { 0 };
union Un
{
char c;
int i;
};
union Un un = { 0 };
从上图我们也能明显看出两者之间的差异
2.4联合体内存大小的计算
联合体的大小至少是最大成员的大小
当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍
例如:
union S
{
char arr[6];
int i;
};
int main()
{
union S s = { 0 };
printf("%zd\n", sizeof(s));
return 0;
}
试着运算一下结构体S的内存空间
下列是运算结果:
发现并不是我们本来想的6
原因是char arr[6]相当于六个char类型的变量,所以数组内存是6,但是对齐数是1,而int i的对齐数是4,发现6并不是4(最大对齐数)的整数倍,所以结构体内存就扩大到了8
由此看出,联合体虽然可以节省空间,但不是绝对的节省
联合体的应用:
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;
};
上述代码是关于礼品券的信息构成的结构体,其中
int stock_number;//库存量 double price; //定价 int item_type;//商品类型
这三种是公用的
其余的结构体里联合体中新的三个小结构体则是三种不同礼品特有的属性
因为这三组属性只在特殊的礼品中才会用到,所以不会同时出现,这就可以使用联合体
而在结构体中创建新的小联合体,以及小联合体中再创建三个小小结构体都是匿名创建
匿名创建是因为再item的变量结构体中,我们们每使用一次,这些结构体和联合体也就使用一次,也只适用于item中,所以可以使用匿名创建。
2.5联合体的应用练习
关于之前判断电脑是大小端字节序存储的代码就可以使用联合体
union U
{
int i;
char c;
};
int main()
{
union U u = { 0 };
u.i = 1;
if (u.c == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}