C语言:构造类型(共用体/联合体,枚举)
共用体/联合体类型
定义
使几个不同的变量占用同一段内存的结构。共用体按定义中需要存储空间最大的成员来
分配存储单元,其他成员也是用该空间,他们的首地址是相同。
定义格式:
union 共用体名称
{
数据类型 变量名; -- 共用体成员
数据类型 变量名;
...
};
公用体的定义和结构体类似:
可以有名字,也可以匿名
共用体在定义时也可以定义公用体变量
共用体在定义时也可以初始化成员
共用体也可以作为形参和返回值类型使用
共用体也可以定义共用体变量
...
也就是说,结构体的语法,共用体都支持
注意:
共用体弊大于利,尽量少用,一般很少用;
共用体变量在某一时刻只能存一个数据,并且也只能取出一个数
共用体和结构体都是自定义数据类型,用法类似于基本数据类型
共用体可以是共用体的成员,也可以是结构体的成员
结构体可以是结构体的成员,也可以是共用体的成员
案例:
/**
* 共用体
*/
#include <stdio.h>
// 定义共用体
union S
{
char a;
float b;
int c;
};// 大小是4字节
// 共用体作为共用体的成员
union F
{
char a;
union S s; // 4字节
};// 大小是4字节
// 共用体作为结构体的成员
struct G
{
int a;
union S s;
};// 大小是8字节
// 定义一个结构体
struct H
{
int a;
char b;
};// 大小是8字节
// 结构体作为结构体成员
struct I
{
int a; // 4
int b; // 4
struct H h; // 8
};// 大小是16字节
// 共用体作为结构体成员
struct J
{
int a;// 4
char b;// 1 + 3
union S s;// 4
};// 大小是12字节
void test1()
{
// 定义共用体类型
union Stu
{
int num;
char sex;
double score;
};
// 定义匿名共用体:匿名共用体一般作为结构体成员或者其他共用体成员
union
{
int a;
char c;
} c;
printf("%lu,%lu\n",sizeof(union Stu),sizeof(c));
}
void test2()
{
union C
{
int a;
char b;
};
// 定义变量
union C c;
// 存数据
c.a = 10;
c.b = 'A';
printf("%d---%d\n",c.a,c.b);// 取数据
c.a += 5;
printf("%d---%d\n",c.a,c.b);// 取数据
union E
{
char *f;
long a;
int b;
} e = {"hello world!"};
printf("%s,%p---%ld,%p---%d\n",e.f,&(e.f),e.a,&(e.a),e.b);
}
int main()
{
test1();
test2();
}
枚举类型
定义
我们一般情况下,定义常量使用宏定义(#define 红名称值),宏定义非常适合没有关联关系的
常量;但是有时候我们可能需要对一组拥有关联关系的量进行定义,比如 ==周一~周日、1月~12
月、方向(上下左右中)等 ,那么使用宏定义,就不是很清晰,这个时候就需要使用到枚举。
枚举的存在就是将多个拥有关系的常量组合到一起,提高代码的可读性。
说明:
枚举类型定义了一组常量,我们在开发中直接使用这些常量。(常用)
当然枚举类型也可以类似于结构体一样定义变量等操作。(不常用)
枚举常量有默认值,从0开始依次+1;我们可以在定义时指定它的默认值,如果个别没有赋值,
可以根据赋值依次+1推导。
特点:
定义了一组常量,类似于定义了多个自定义常量(宏定义)
提供了代码的可读性。
定义语法:
定义枚举类型名以后就可以定义该枚举类型的变量。
enum 枚举类型名 变量列表;
在定义枚举类型的同时定义该枚举类型的变量。
enum 枚举类型名{枚举元素列表} 变量列表;
直接定义枚举变量
enum {枚举元素列表} 变量列表;
案例:
#include <stdio.h>
void test1()
{
// 定义一个枚举类型
// 枚举类型名一般首字母大写,主要是根枚举变量区分
enum Week
{
// 定义枚举元素,元素命名要符合标识符命名规则,同时采用大写字母+下划线方式命名
SUN=10,MON,TUE,WED,THU,FRI,SAT
};
// 1.直接访问枚举元素
printf("%d,%d,%d\n",SUN,WED,SAT);
// 2.定义枚举类型的变量(先定义变量,后赋值)
enum Week week;
// 初始化
week = TUE;// 一定是这个枚举类型中定义的元素
printf("%d\n",week);
// 3.定义枚举类型变量的同时赋值(定义变量和赋值同时进行)
enum Week week1 = THU;
printf("%d\n",week1);
enum H
{
A,B,C // 多个元素使用逗号分隔
} x,y;
x = B;
y = C;
printf("x=%d,y=%d\n",x,y);// 1,2
}
void test2()
{
// 定义枚举
enum CaiQuan
{
SHI_TOU,JIAN_DAO,BU
};
printf("请输入0~2之间的整数:\n[0-石头,1-剪刀,2-布]\n");
int number;
scanf("%d",&number);
switch(number)
{
case SHI_TOU:
printf("石头\n");
break;
case JIAN_DAO:
printf("剪刀\n");
break;
case BU:
printf("布\n");
break;
}
}
int main(int argc,char *argv[])
{
test1();
test2();
return 0;
}
typedef
说明:给类型重命名,不会影响到类型本身
作用:给已有的类型起别名
格式:
typedef 已有类型名 新别名;
使用:
// 方式1:先定义结构体类型,再重命名
// 定义一个结构体类型
struct Student
{
int id;
char *name;
char sex;
int age;
};
// 类型重命名
typedef struct Student Stu;
// 定义结构体变量
struct Stu stu = {1,"张三",'w',21};
// 方式2:定义结构体的同时重命名
typedef struct PersonInfo
{
int a;
double b;
} Per; // 结构体类型的别名,本质上还是数据类型
// 定义变量
struct Per per = {2,5};
应用场景:
数据类型复杂(结构体、共用体、枚举、结构体指针、无符号的长整型)时使用
为了跨平台兼容性,例如:
1. size_t:类型重命名后的数据类型: typedef unsigned long size_t;
2. unit_16:类型重命名后数据类型
案例:
//类型重命名
#include <stdio.h>
struct Student
{
int age;
char* name;
double score;
int arr[3];
};
typedef struct Student Stu_t;// 数据类型重命名
typedef Stu_t* pStu_t;// 结构体指针重命名
void test1()
{
Stu_t s1 = {23, "zhangsan", 23.33, {11, 22, 33}};
printf("%d, %s, %f, %d\n", s1.age, s1.name, s1.score, s1.arr[0]);
//Stu_t *p = &s1;
Stu_t* p;
p = &s1;
pStu_t p2;
p2 = p;
printf("%d, %s, %f, %d\n", p2->age, p2->name, p2->score, p2->arr[0]);
}
int main()
{
test1();
return 0;
}