赞
踩
C 语言提供了多种基本数据类型,如整型、浮点型、字符型等,以及一些构造类型,如数组、指针、函数等。但是,有时候这些类型还不足以表达一些复杂的数据结构或者逻辑关系,因此,C 语言也允许我们根据实际需要自定义一些数据类型,以便更好地解决问题。
本文将介绍三种自定义类型,分别是枚举类型、结构体类型、联合(共用体)类型。
枚举类型是一种用来表示一组有限的离散值的类型,它可以用来定义一些常量集合,如星期、月份等。枚举就是把可能的取值一一列举。
枚举类型的定义格式如下:
enum 枚举类型名 {枚举元素表};
其中,enum
是关键字,枚举类型名
是用户自定义的标识符,枚举元素表
是由逗号分隔的多个枚举元素组成,每个枚举元素可以看作是一个整型常量,它们的值默认从 0 开始依次递增,也可以在定义时指定。
例如,定义星期时:
- enum Weekday
- {
- MON, //0
- TUE, //1
- WED, //2
- THU, //3
- FRI, //4
- SAT, //5
- SUN //6
- }; // 定义一个星期的枚举类型
此时的星期所对应的数字并不对,一个星期应该是从1开始到7结束,而此时是从0开始6结束的,我们只需要将Mon(星期一)赋值为1即可,后面的星期仍会依次增加1。
修改后的代码如下:
- enum Weekday
- {
- MON = 1, //1
- TUE, //2
- WED, //3
- THU, //4
- FRI, //5
- SAT, //6
- SUN //7
- }; // 定义一个星期的枚举类型
请注意,枚举类型并不是只能赋值连续的数值,枚举类型会在赋值处重新开始累加。另外,枚举变量只能用枚举常量来赋值(用int类型赋值枚举变量的行为,在C中不会报错但在C++中会报错)。
例如:
- enum Color
- {
- RED = 1, //1
- YELLOW, //2
- BLUE = 4, //4
- GREEN = 10,//10
- };
- enum Color clr = BLUE;//4
- clr = 5;//error
#define
指令。结构体类型是一种用来表示一组相关的数据的类型,它可以将不同类型的数据成员组织到一个整体中,适合对复杂的数据进行处理。
结构体类型的定义格式如下:
struct 结构体类型名 {数据类型1 成员1; 数据类型2 成员2; ... 数据类型n 成员n;};
其中,struct
是关键字,结构体类型名
是用户自定义的标识符,数据类型i
和 成员i
分别表示结构体中的第 i 个成员的数据类型和名称,它们可以是任意合法的数据类型,包括基本类型、数组、指针、函数、枚举类型、结构体类型等。
例如:
- struct Stu // 定义一个学生的结构体类型
- {
- char name[20]; // 姓名
- int age; // 年龄
- char sex[5]; // 性别
- double score; // 成绩
- };
结构体类型名可以省略,省略后创建的就是匿名结构体。
例如:
- struct // 定义一个匿名结构体
- {
- int i;
- float f;
- char str[20];
- };
定义了结构体类型后,就可以用它来定义结构体变量。
如:
struct Stu stu1, stu2; // 定义两个学生的结构体变量
结构体变量可以在定义时或者之后赋值,赋值时需要使用大括号将各个成员的值按照顺序包含起来。
如:
struct Stu stu = {"张三", 18, "男", 95.5}; // 定义并初始化一个学生的结构体变量
结构体变量可以通过'.'操作符来进行引用、赋值、输出等操作。
如:
- printf("姓名:%s\n", stu.name); // 引用结构体变量的成员
- printf("年龄:%d\n", stu.age);
- printf("性别:%s\n", stu.sex);
- printf("成绩:%.2f.\n", stu.score);
将结构体变量的地址赋值给一个指针p后也可以通过'->'来进行上述操作。
如:
- struct Stu *p = &stu;//定义结构体指针p,并将结构体变量stu的地址赋值给p
- printf("姓名:%s\n", p->name); // 引用结构体变量的成员
- printf("年龄:%d\n", p->age);
- printf("性别:%s\n", p->sex);
- printf("成绩:%.2f.\n", p->score);
结构体变量也可以在定义的时候就赋值,还可以使用'.'操作符来改变赋值的顺序。
例如:
- struct SN
- {
- char c;
- int i;
- }sn1 = { 'A', 1 }, sn2 = { .i = 2 , .c = 'B' };
C语言中结构体的自引用的方法是在结构体内部,包含指向自身类型结构体的指针。这样可以实现链表等数据结构。
错误的自引用方式:
- struct Node {
- int data;
- struct Node next;
- };
正确的自引用方式:
- struct Node {
- int data; //数据域
- struct Node *next; //指针域,指向下一个结点
- };
C语言中结构体的对齐是指结构体中的成员变量在内存中的存放方式,它受到两个因素的影响:自身对齐值和指定对齐值
#pragma pack(n)
宏定义来设定的一个整数,它表示结构体中的成员变量的对齐方式,n只能是2的幂次方,例如1,2,4,8,16等。
结构体的对齐遵循以下三个原则:
下面举一个例子来说明结构体的对齐过程,假设在32位系统上,指定对齐值为4,有如下结构体定义:
- struct test {
- char a; // 1 byte
- int b; // 4 bytes
- short c; // 2 bytes
- };
根据对齐原则,我们可以得到以下结果:
同样,根据对齐原则,我们稍微调整一下结构体成员的顺序便可减少结构体所占内存的大小:
- struct test {
- char a; // 1 byte
- short c; // 2 bytes
- int b; // 4 bytes
- };
分析可知,修改后的代码使结构体所占内存大小减少4个字节。因此我们在创建结构体类型时应该注意结构体成员的排列顺序。
C语言中的位段(bit field)是一种特殊的结构体成员,它可以指定占用的二进制位数,从而节省内存空间。
位段的声明和使用方法如下:
- //声明一个位段结构体
- struct A {
- int a: 3; //a占用3位
- int b: 4; //b占用4位
- int c: 5; //c占用5位
- };
- //使用一个位段变量
- struct A bf;
- bf.a = 5; //赋值
- bf.b = 10;
- bf.c = 15;
- printf("%d, %d, %d\n", bf.a, bf.b, bf.c); //输出
位段的存储方式和对齐规则取决于编译器的实现,不同的编译器可能有不同的结果。
一般来说,位段的存储遵循以下原则:
注意:跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。
联合类型是一种特殊的数据类型,它可以在同一段内存空间中存储不同的数据类型,但是每次只能使用其中一个成员的值。联合类型的优点是节省内存空间,缺点是不能同时操作多个成员。联合类型的定义和使用方法与结构体类似,只是关键字从 struct 改为 union。
例如:
- union Data
- {
- int i;
- double d;
- char str[20];
- };
- union Data data; //定义一个联合变量
- data.i = 10; //给整型成员赋值
- data.f = 3.14; //给浮点型成员赋值,会覆盖整型成员的值
- data.str = "Hello"; //给字符串成员赋值,会覆盖浮点型成员的值
结构体向double对齐,20个char一共是20字节,对齐后是24字节。n是单独的4字节,d是单独的8字节,由于是union,所以n,d与s共用空间,只取最长的元素,故占用24字节。
以上,就是C语言中有关枚举类型,结构体类型和联合(共用体)类型的介绍,希望对大家有所帮助!
如有错误,欢迎在评论区指出!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。