随风而动,随遇而安......
C语言共用体与枚举类型-学习三十
02/25
本文最后更新于
2022年08月13日,已超过
823天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!
共用体类型
- 共用体也是一种构造类型,将不同类型的数据组合在一起。
但与结构体类型不同,在共用体内的不同成员占用同一段存储区,成员之间互相覆盖,即在同一时刻只有一个成员起作用。 - 为共用体变量分配空间的大小是以所有成员中占用空间字节数最多的成员为标准。
- 共用体类型的声明及变量的定义
共用体类型的声明与结构体的声明完全相同,只是关键字为union。 - 共用体类型的声明格式:
union 共用体名{
数据类型 成员名1;
数据类型 成员名2;
...
数据类型 成员名n;
};
- 例如:
union data {
int i;
char c;
float f;
};
- 共用体变量的定义方式与结构体变量的定义方式相似,也有3种方式:
- 1.类型声明与变量定义分开
union data {
int i;
char c;
float f;
};
union data d1, d2;
- 2.在声明类型的同时定义变量
union data {
int i;
char c;
float f;
}d1, d2;
- 3.直接定义共用体类型的变量,不给出共用体名
union
{
int i;
char c;
float f;
}d1, d2;
共用体变量初始化
- 对于共用体变量,在定义的同时,可以初始化,但是初始化只能对第一个成员初始化。
例如:
union data d1={10};
即 共用体里的int i = 10;
共用体变量中成员的引用
- 与结构体变量成员引用的方式相同,也使用 “->” 和 “.” 两种运算符来实现;
格式:
共用体变量名.成员名
共用体指针->成员名
例如:
union data d1, *tpd;
pd = &d1;
对d1成员的引用可以是:
d1.i
或pd ->i
、d1.c
或pd ->c
、d1.f
或pd ->f
- 同类型的共用体变量之间可以互相赋值。
- 例子:
#include <stdio.h>
union data{
int i;
char c;
float f;
};
struct data2{
int i;
char c;
float f;
};
void main()
{
union data ud;
struct data2 sd;
ud.i = 10; ud.c = 'A'; ud.f = 20;
sd.i = 10; sd.c = 'A'; sd.f = 20;
printf("size of ud: %d, size of sd: %d\n", sizeof ud, sizeof sd);
printf("ud.i: %d,ud.c: %c,ud.f: %f\n", ud.i, ud.c, ud.f);
printf("sd.i: %d,sd.c: %c,sd.f: %f\n", sd.i, sd.c, sd.f);
}
从上面的运行结果可看出
- 对共用体变量成员的赋值,保存的是最后的赋值前面对其他成员的赋值均被覆盖。
- 由于结构体变量的每个成员拥有不同的内存单元,因而不会出现这种情况。
共用体与结构体比较
- 1.结构体类型是一种复杂而灵活的构造数据类型,它可以将多个相互关联但类型不同的数据项作为一个整体进行处理。
定义结构体变量时,每一个成员都要分配空间存放各自的数据。 - 2.共用体是另一种均造数据类型,定义共用体变量时,只按占用空间最大的成员来分配空间,
在同一时刻只能存放一个成员的值。 - 3.共用体变量的定义形式与结构体变量的定义形式类似,都有三种形式,只是关键字不同。
- 4.结构体变量通过初值列表实现对变量中的成员初始化。
共用体变量只能对第一个成员初始化。 - 5.共用体成员的访问方式与结构体相同,成员的访问通过运算符 “.” 和 “->” 实现。
- 例子
设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。现要求把它们放在同一表格中
#include <stdio.h>
#pragma warning (disable:4996)
struct{
int num;
char name[10];
char sex;
char job;
union {
int banji;
char position[10];
}category;
}person[2];
void main()
{
int i;
for (i = 0; i < 2; i++) {
printf("请输入信息:\n");
scanf("%d %s %c %c",
&person[i].num, &person[i].name, &person[i].sex, &person[i].job);
if (person[i].job == 's') {
scanf("%d", &person[i].category.banji);
}
else if(person[i].job=='t'){
scanf("%s", &person[i].category.position);
}
else {
printf("输入错误!");
}
}
printf("\n");
for (i = 0; i < 2; i++) {
if (person[i].job == 's') {
printf("%-6d %-10s %-3c %-3c %-6d\n",
person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.banji);
}
else {
printf("%-6d %-10s %-3c %-3c %-6s\n",
person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.position);
}
}
}
枚举类型
- 如果一个变量只有几种可能的值,则可以定义为枚举(enumration)类型,
所谓“枚举”就是把可能的值一一列举出来,变量的取值限于列举出来的值的范围内。 - 枚举类型声明格式:
enum 枚举类型名{
枚举元素列表 // 枚举元素之间以逗号间隔
};
枚举变量的定义:
- 1.先声明枚举数据类型,再定义枚举变量
enum week{
sun , mon ,tue , wed , thu , fri , sat
};
enum week workday;
- 2.声明枚举类型的同时定义枚举变量
enum week{
sun , mon ,tue , wed , thu , fri , sat
}workday;
- 3.不指定枚举类型名,直接定义枚举变量
enum {
sun , mon ,tue , wed , thu , fri , sat
}workday;
- 枚举变量workday的值只能在枚举元素sun,mon, .… sat之间取其中一个,不能超出这个范围。
- 枚举类型使用时需注意以下几点:
1.枚举元素是常量,有固定的值,不能将其作为变量使用
- 例如:
sun=0; mon = 1错误,不能为枚举元素赋值
- 例如:
2.每一个枚举元素都代表了一个整数,编译程序按定义时的顺序默认它们的值为0、1、2、3......
上面的定义中,sun的值为0、mon的值为1、.....sat的值为6。例如:
- 如果有赋值语句:
workday = mon;
- 相当于:
workday = (enum week)1;
- 如果有赋值语句:
- 一个整数不能直接赋给一个枚举变量先进行强制类型转换才能赋值。
3.如果不希望使用默认的值,也可以在声明数据类型时指定值。
例如
- 指定枚举元素sun的值为7,mon的值为1,tue的值为2,以后顺序加1,sat为6。
enum {
sun=7, mon=1, tue=2, wed , thu , fri , sat
}workday;
4.枚举值,可以用来作判断比较
例如:
if(workday == mon)
- 5.不能有两个相同名字的枚举元素,枚举元素也不能与符号常量和变量同名。
用typedef声明新类型名
- 1.简单地用一个新的类型名代替原有的类型名
typedef int Integer;
typedef float Real;
int i,j;
float a,b;
// 等价
Integer i,j;
Real a,b;
- 2.命名一个简单的类型名代替复杂的类型表示方法
- 命名一个新的类型名代表结构体类型:
typedef struct{
int month;
int day;
int year;
}Date; // 声明新类型名Date,它代表上面指定的一个结构体类型
Date birthday;
Date *p; // p为指向此结构体类型数据的指针
- 命名一个新的类型名代表数组类型
typedef int Num[100]; //声明NUM为整型数组类型
Num a; //定义a为整型数组变量
- 命名一个新的类型名代表一个指针类型
typedef char *String; // 声明String为字符指针类型
String p,s[10]; // p为字符指针变量,s为指针数组
- 命名一个新的类型名代表指向函数的指针类型
typedef int (*Pointer)(); // 声明Pointer为指向函数的指针类型,该函数返回整型值
Pointer p1,p2; // p1,p2为Pointer类型的指针变量
声明一个新的类型名的方法:
- 1.先按定义变量的方法写出定义体
int i;
- 2.将变量名换成新类型名(将i换成Count)
- 3.在最前面加 typedef
- 4.得到
typedef int Count;
- 1.先按定义变量的方法写出定义体
以定义上述的数组类型为例来说明:
- 1.先按定义数组变量形式书写:
int a[100];
- 2.将变量名a换成自己命名的类型名:
int Num[100];
- 3.在前面加上typedef,得到
typedef int Num[100];
- 4.用来定义变量:
Num a;
- 5.相当于定义了:
int a[100];
- 1.先按定义数组变量形式书写:
对字符指针类型,也是:
char *p;
char *String;
typedef char *String;
String p;
说明:
1.以上的方法实际上是为特定的类型指定了一个同义字(synonyms)。
例如:
typedef int Num[100];
Num
是int [100]
的同义词typedef int (*Pointer)();
Pointer
是int(*)()
的同义词
- 2.用typedef只是对已经存在的类型指定一个新的类型名,而没有创造新的类型。
- 3.用tyoedef声明数组类型、指针类型、结构体类型、共用体类型、枚举类型等,使得编程更加方便。
4.typedef 与 #define 表面上有相似之处
typedef int COUNT
#define COUNT int
- 作用都是用COUNT代表int。#define是在预编译时处理,只能作简单的字符串替换,
而typedef是在编译时处理的,为已有类型命名。
- 5.当不同源文件中用到同一类型数据时(数组、结构体等),常用typedef声明一些数据类型。把它们单独放在一个头文件中。
- 6.使用typedef名称有利于程序的通用与移植。有时程序会依赖于硬件特性,用typedef类型就便于移植。