共用体
😀什么是共用体
共用体(联合体)是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。各成员共享一段内存空间注意这里所谓的共享不是指把多个成员同时装入一个联合变量内,而是指该联合变量可被赋予任一成员值,但每次只能赋一种值,赋入新值则冲去旧值,共用体变量中起作用的成员是最后一次存放的成员,在存入一个新成员后,原有成员就失去作用,共用体变量的地址和它的各成员的地址都是同一地址
union [name](联合体名) name是可选的
{
成员表
};
成员表中含有若干成员,成员的一般形式为: 类型说明符 成员名
成员名的命名应符合标识符的规定。
union Data
{
int i;
double f;
char str[20];
} data; //定义共用体类型的同时顶定义变量
😍现在 Data所有的成员共享一个空间,同一时间只有一个成员是的值有效的,Data 类型的变量可以存储一个整数、
一个浮点数,或者一个字符串。这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。
您可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型。
共用体占用的内存应足够存储共用体中最大的成员。例如,在上面的实例中,
Data 将占用 20 个字节的内存空间,因为在各个成员中,字符串所占用的空间是最大的
😨 union中的元素不存在内存对齐的问题,因为union中实际只有1个内存空间,都是从同一个地址开始的(开始地址就是整个union占有的内存空间的首地址),所以不涉及内存对齐。
🤯注意:
1、不能把共用体变量作为函数参数,也不能是函数带回共用体变量,但可以使专用指向共用体变量的指针
2、所有成员占用同一段内存,修改一制个成员会影响其余所有成员。
😬共用体的使用
🤜共用体的访问:共用体访问成员的值时一般使用.运算符,指针时用->运算符(和结构体是一样的)
typedef union _node { int a; double b; char c; union _node *p; }NODE; int main(void) { NODE a;//定义变量 NODE t; a.b;//用.访问 t.p->a;//指针用->访问
共用体的使用规则几乎和结构体strtct的规则用法一样,只不过是内部表示的不同。
可配合共用体进行嵌套使用:
//定义一个共用体存储班级或职务 union Post { char class[20];//班级 char position[20];//职务 }Post; //定义一个结构体存储基本信息 typedef struct { char name[20]; //名字 int phone; //电话 char gender[20]; //性别 char Job[20]; //职业 union Post join; // 存储学生或老师的班级和职务 }Person;
手法:班级和职务根据选择的职业来进行选择,每个结构体里的共用体都不一样
😌共用体的作用
1️⃣节省内存,有两个很长的数据结构,不会同时使用,比如一个表示老师,一个表示学生,如果要统计教师和学生的情况用结构体的话就有点浪费了!用结构体的话,只占用最长的那个数据结构所占用的空间,就足够了!
2️⃣实现不同类型数据之间的类型转换,遇到各种类型的数据共用存储空间,很方便的实现了不同数据类型之间的转换,不需要显示的强制类型转换。
3️⃣其他:确定CPU的模式:大端、小端模式确定
4️⃣大小端不同,则存储的方式也存在差别,比如int需要4个字节,而char只需要1个字节,根据1个字节所在的具体位置即可判定CPU的模式
枚举体
😀什么是枚举类型
枚举类型(enumerated type)声明符号名称来表示整型常量。使用enum关键字,可以创建一个新“类型”并指定它可具有的值。枚举类型的目的是提高程序的可读性。它的语法与结构的语法相同。
注:(实际上,enum 常量是int类型,因此,只要能使用int类型的地方就可以使用枚举类型)
🤣语法格式
enum 枚举类型标识名 {枚举成员1, 枚举成员2, … , 枚举成员n};
enum DAY {MON, TUE, WED, THU, FRI, SAT, SUN}; enum spectrum {red = 1, orange, yellow, green, blue, violet}; enum DAY COLOR = MON; enum spectrum color = red; printf("%d\n", COLOR); // 0 printf("%d\n", color); // 1
🔯枚举型是一个集合,集合中的元素(枚举成员)是一些命名的整型常量,元素之间用逗号,隔开。
🔯 DAY, spetrum 是一个标识符,可以看成这个集合的名字,是一个可选项,即是可有可无的项。
🔯第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。
🔯可以人为设定枚举成员的值,从而自定义某个范围内的整数。
🔯 枚举型是预处理指令#define的替代。
🔯 类型定义以分号;结束。
😺方法一、枚举类型的定义和变量的声明分开
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN }; enum DAY tomorrow; //变量tomorrow的类型为枚举型enum DAY enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum
😸方法二:类型定义与变量声明同时进行
enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。 { saturday, sunday = 0, monday, tuesday, wednesday, thursday, friday } workday; //变量workday的类型为枚举型enum DAY enum BOOLEAN { false, true } end_flag, match_flag; //定义枚举类型并声明了两个枚举型变量 end_flag, match_flag
😹方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明
typedef enum workday { saturday, sunday = 0, monday, tuesday, wednesday, thursday, friday } workday; //此处的workday为枚举型enum workday的别名 workday today, tomorrow; // 变量today和tomorrow的类型为枚举型workday,也即enum workday // enum workday中的workday可以省略:
😻也可以用这种方式:
typedef enum workday { saturday, sunday = 0, monday, tuesday, wednesday, thursday, friday }; workday today, tomorrow; //变量 today和 tomorrow的类型为枚举型workday,也即enum workday
🧐枚举声明的注意事项
注意:同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。
反面教材:
typedef enum { wednesday, thursday, friday } workday_1; typedef enum WEEK { wednesday, sunday = 0, monday, } workday_2; //在枚举类型 workday_1 与 枚举类型 workday_2中 都有枚举成员 wednesday;
注:在同一个程序中不能定义相同的枚举类型名,以及所有的枚举成员不能相同,使得枚举类型名可以不定义。
🤓枚举变量的赋值
(1) 默认情况下枚举列表中的常量都被赋予0、1、2等。因此,下面的声明中nina的值是3:
enum kids {nippy, slats, skippy, nina, liz};(2) 在枚举声明中,可以为枚举常量指定整数值:
enum levels {low = 100, medium = 500, high = 2000};(3) 如果只给一个枚举常量赋值,没有对后面的枚举常量赋值,那么后面的常量会被赋予后续的值。
例如,假设有如下的声明:
enum feline {cat, lynx = 10, puma, tiger};那么,cat的值是0(默认),lynx、puma和tiger的值分别是10、11、12。
使用案例:
枚举类型的目的是为了提高程序的可读性和可维护性
(一)类型定义,变量声明,赋初值同时进行。
#include <stdio.h> /* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */ enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday = MON, today = TUE, tomorrow = WED; /* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */ int x = 10, y = 20, z = 30; void main() { printf("%d %d %d \n", x, y, z); //输出:10 20 30 printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3 }
🤯枚举类型与sizeof运算符
#include <stdio.h> enum escapes { BELL = '\a', BACKSPACE = '\b', HTAB = '\t', RETURN = '\r', NEWLINE = '\n', VTAB = '\v', SPACE = ' ' }; enum BOOLEAN { FALSE = 0, TRUE } match_flag; void main() { printf("%d bytes \n", sizeof(enum escapes)); //4 bytes printf("%d bytes \n", sizeof(enum BOOLEAN)); //4 bytes printf("%d bytes \n", sizeof(match_flag)); //4 bytes printf("%d bytes \n", sizeof(SPACE)); //4 bytes printf("%d bytes \n", sizeof(FALSE)); //4 bytes printf("%d bytes \n", sizeof(0)); //4 bytes }
总结:无论是枚举类型、枚举成员、枚举类型变量 都是四个字节(int类型)。
typedef关键字与结构体、结构体指针
🐬使用typedef定义结构体
知识点1:
🔑typedef用来定义新的数据类型,通常typedef与结构体的定义配合使用。使用typedef的目的使结构体的表达更加简练(所以说typedef语句并不是必须使用的。)🔑用大白话来说:
▶ struct 是用来定义新的数据类型——结构体
▶ typedef是给数据类型取别名。
定义一个名字为TreeNode的结构体类型(现在并没有定义结构体变量,并不占用内存空间)
struct TreeNode // 结构体类型 { int Element; struct TreeNode* LeftChild; //结构体成员 struct TreeNode* RightChild; };
为结构体起一个别名Node,这时Node就等价于struct TreeNode
typedef struct TreeNode Node;
将结构体的定义和typedef语句可以连在一起写:
typedef struct TreeNode //结构体类型 { int Element; //结构体成员 struct TreeNode* LeftChild; struct TreeNode* RightChild; }Node; // Node 是 struct TreeNode 的别名
注意:Node 是 struct TreeNode 的别名
注意 :不要与“定义结构体类型的同时定义结构体类型变量”混淆:
使用typedef关键字定义结构体类型 定义结构体类型的同时定义结构体类型变量typedef struct student { int age; int height; }std; //std相当于struct student struct student { int age; int height; }std1,std2; //定义了student数据类型的结构体和std1、std2结构体变量
🐬使用typedef定义结构体指针
知识点1:
使用typedef关键字用一个单词Node代替struct TreeNode,并定义指向该结构体类型的指针PtrToTreeNode:struct TreeNode { int Element; struct TreeNode* LeftChild; struct TreeNode* RightChild; }; typedef struct TreeNode Node; //用Node代替struct TreeNode Node *PtrToTreeNode; //定义指针
将结构体的定义和typedef连在一起写,再次缩短代码:
typedef struct TreeNode { int Element; struct TreeNode* LeftChild; struct TreeNode* RightChild; }Node; //定义结构体并用Node代替struct TreeNode Node *PtrToTreeNode; //定义指针
结尾:
C语言的学习迎来了尾声,大家学习的怎么样了!!!!