目录
构造数据类型:用户自己建立的数据类型(自定义数据类型)。
C语言中的构造数据类型有:数组类型、结构体类型、共用体类型和枚举类型。
用户根据自己的需求建立的由不同类型数据组成的数据类型。
即,
结构体这种数据类型它能根据用户需要,方便的存储各种各样的信息。
■. 结构体类型的声明
(1)声明时定义结构体变量
- struct 结构体类型名
- {
-
- 成员列表;
-
- }结构体变量名; // 可以在声明时定义结构体变量名
- // 声明时未定义变量的话,分号(;)勿漏
(2)先声明后定义结构体变量
基本格式:结构体类型名 变量名;
- struct student s1;
-
- //s1.id=12345;
■. 结构体成员的使用
基本格式:结构体变量名.成员名
结构体成员引用符:.
例如:
- #include
- struct pananzhongxue //构造结构体,名为“pananzhongxue”
- {
- int id;
- int age;
- float zongscore;
- int gender;
- char name[10];
- }s1 = {085422103,19,536,1,"chenchen"}, s2; //声明时定义结构体变量s1,s2,
- //并对s1初始化赋值
- int main()
- { //输出“pananzhongxue”结构体类型中的s1的各个数据
- printf("%d\t%d\t%d\t%f\t%s\n", s1.id, s1.age, s1.gender, s1.zongscore, s1.name);
- return 0;
- }
说明:
(1) struct 为结构体关键字
(2)struct pananzhongxue 为结构体类型名
(3)id、age... 为结构体成员名
(4)s1、s2 为结构体变量
区分清楚:结构体类型名、结构体成员名以及结构体变量
■. 结构体变量的定义:
(1)可以在声明时直接定义结构体变量;
(2)也可以先声明后定义结构体变量(用数据类型名定义结构体变量);
- #include
- struct pananzhongxue
- {
- int id;
- int age;
- float zongscore;
- int gender;
- char name[10];
- }s1, s2; //声明时定义结构体变量s1,s2
-
- int main()
- { //声明后定义结构体变量s3
- struct pananzhongxue s3 = {085422103,19,536,1,"xiaohei"};
- printf("%d\t%d\t%d\t%f\t%s\n", s3.id, s3.age, s3.gender, s3.zongscore, s3.name);
- return 0;
- }
结构体类型的数组
■. 结构体数组元素的使用:
结构体数组名[数组下标].成员变量名
例如:
- #include
- struct student
- {
- int id;
- int age;
- int height;
- int weight;
- float score;
- }arr1[3]; // 声明一个结构体数组arr1[3]
-
- int main()
- {
- arr1[0].id = 085422103;
- printf("%d\n", arr1[0].id);
- return 0;
- }
■. 注意数组类型的成员
1. 数组类型int的成员,单个数据元素可以直接进行赋值:
- #include
- struct pananzhongxue
- {
- int id;
- int age;
- float score[3];
- int gender;
- char name[10];
- }s1, s2;
-
- int main()
- {
- s2.age[0] = 15; //数组类型单个数据元素赋值
- s2.age[1] = 11;
- s2.age[2] = 10;
- printf("%f\t%f\t%f\n", s2.age[0], s2.age[1], s2.age[2]);
- return 0;
- }
2. 数组类型(如char)的成员不能直接赋值,
可以用字符串拷贝函数strcpy来完成字符数组的赋值:
- #include
- #include
//输入字符串处理函数头文件 - struct pananzhongxue
- {
- int id;
- int age;
- float score;
- int gender;
- char name[10];
- }s1,s2;
-
- int main()
- {
- strcpy(s1.name, "cc"); //用字符串拷贝函数strcpy来赋值
- printf("%s\n", s1.name);
- return 0;
- }
■. 相同结构体类型的成员可以相互赋值:
- #include
- #include
- struct pananzhongxue
- {
- int id;
- int age;
- float score[3];
- int gender;
- char name[10];
- }s1,s2;
-
- int main()
- {
- s2.score[0] = 105;
- s2.score[1] = 91;
- s2.score[2] = 110;
-
- s1.score[0] = s2.score[2]; //进行相互赋值
- s1.score[2] = s2.score[0];
- s1.score[1] = s2.score[1];
-
- printf("%f\t%f\t%f\n", s2.score[0], s2.score[1], s2.score[2]);
- printf("%f\t%f\t%f\n", s1.score[0], s1.score[1], s1.score[2]);
- return 0;
- }
- #include
- struct student
- {
- int id;
- char name[10];
- };
-
- int main()
- {
- struct student arr1[2]={854221,"chenchen",854222,"chenhnch"};
- printf("id\tname\n);
- for(int i=0;i<2;i++)
- {
- printf("%d\t%s\n",arr1[i].id,arr1[i].name);
- }
- return 0;
- }
关键字typedef:用于给数据类型关键字取别名
typedef的基本格式:
typedef 数据类型名 别名;
typedef取的别名也需要遵循标识符的命名规则。
typedef可以给一个数据类型取多个别名
typedef一般使用在数据类型名比较长的情况下
例如:
- #include
- typedef struct chenchenchenchenchen
- {
- int height;
- int weight;
- }xxx;
-
- int main(void)
- {
- xxx s1; //取别名后需再定义结构体变量名
- s1.height = 172;
- printf("%d\n", s1.height);
- return 0;
- }
一维数组类型的定义格式:
typedef 数据类型 数组名[常量];
例如:
- #include
- typedef struct chenchenchenchenhcne
- {
- int id;
- char name[20];
- char gender[4];
- int age;
- float score[3];
- }CC;
-
- typedef int I[10]; // 定义了一个数组类型I
- // 元素类型为int
- // 元素个数为10
- int main(void)
- {
- I a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 相当于int a[10]={...};
- // I换成a即可
- for (int i = 0; i < 10; i++) // 可多次定义对象(数组名)
- {
- printf("%d\t", a[i]);
- }
- putchar('\n');
- return 0;
- }
计算结构体内存大小时要考虑其内存布局。
系统为了提高计算机访问数据的效率,
在安排结构体中的每个成员时采用内存对齐的方法。
结构体在内存中按统一单元进行存放,
每个单元的大小取决于结构体成员中最大的基本数据类型大小。
即,在结构体中,对不同成员类型的大小,在内存中采取内存对齐的方法以提高运行效率
例如:
- #include
- typedef struct student
- {
- short id; //2
- short age; //2
- char name[5]; //5
- int height; //4
- int weight; //4
- float score; //4
- }xxx;
-
- int main()
- {
- printf("%d\n", sizeof(xxx)); // 24
- return 0;
- }
内存储存如下:

补充: 为什么要内存对齐?
1.为了提高代码的可移植性,和提升CPU访问内存的效率(本质:以空间换时间)。
2.不是所有的硬件平台都能访问任意地址上的数据,某些硬件平台只能在某些地址访问某些特定类型的数据,否则会抛出硬件异常,以及遇到未对齐的边界直接就不进行读取数据。
把一个结构体的变量作为另一个结构体的成员。
例如:
- #include
- struct student
- {
- int id;
- int height;
- int weight;
- char gender[3];
- char name[10];
- float score[3];
- }s1,s2,s3;
-
- struct teacher
- {
- int id;
- int height;
- int weight;
- char gender[3];
- char name[10];
- struct student s1; // 结构体嵌套
- }t1,t2,t3; // 结构体类型student中的变量s1是结构体类型teacher中的成员
- // teacher中的成员
- int main()
- {
- t1.s1.id = 85422103;
- printf("%d\n",t1.s1.id);
- return 0;
- }
■. 注意,一个结构体类型中可以有本身这种结构体类型的成员吗?
- struct teacher
- {
- int id;
- int height;
- int weight;
- char gender[3];
- char name[10];
- struct teacher t2; //可以吗?
- };
-----会报错:不允许使用不完整的类型。
用同一段内存单元存放不同类型的变量。
同一个内存单元中,它们在内存中所占字节数不同,但共用同一段内存地址。
一般格式:
- union 共用体类型名
- {
- 成员列表;
- }共用体变量;
(1)声明时定义;
(2)声明后定义;共用体类型名 变量名;
例如:
- #include
- union student
- {
- int id;
- float score;
- char a;
- double b;
- }t1,t2;
-
- int main()
- {
- printf("%d\n", &(t1.id)); //所有输出结果相同
- printf("%d\n", &(t1.score)); //为共用内存的首地址
- printf("%d\n", &(t1.a));
- printf("%d\n\n", &(t1.b));
-
- printf("%d\n", &(t1.b)); //下面也是一样的
- printf("%d\n", &t1.b); //且每次运行会重新随机申请存储空间
- printf("%d\n", &t1);
- return 0;
- }
整个共用体类型所占内存是最大成员所占的内存空间(或其整数倍)
例如:
- #include
- union student
- {
- int id; //4
- float score[10]; //4*10
- char a; //1
- double b; //8
- }t1,t2;
-
- int main()
- {
- printf("%d\n", sizeof(union student)); //8*5
- return0;
- }
或
- #include
- union student
- {
- int id;
- float score;
- char a;
- double b;
- }t1,t2;
-
- int main()
- {
- printf("%d\n", sizeof(union student)); //8
- return 0;
- }
注意:所占内存空间为最大基本数据类型的最小整数倍
例如:
- #include
- union student
- {
- int id;
- float score;
- char a[10];
- double b;
- }t1,t2;
-
- int main()
- {
- printf("%d\n", sizeof(union student)); //16
- return0;
- }
存储和读取数据时:
- #include
- union student
- {
- int id;
- float score;
- char a;
- double b;
- }t1,t2;
-
- int main()
- {
- t1.id = 0x11223344;
- t1.a = 0x55;
- printf("%x\n",t1.id); //11223355
- printf("%x\n",t1.a); //55
- return 0;
- }
大端模式:

共用体变量只能给一个成员初始化赋值,
共用体同一时刻只能保存一个成员的数据(数据相应位置覆盖)
- 枚举类型enum:将类型中所有可能的取值一一列举出来,
-
- 枚举值只能从列举出的范围内取值,
-
- 否则没有意义。
枚举类型可以初步简单理解为取值受限的整型,其值被按照整型数据来处理和运算。
如果一个变量只有几种可能的值,就可以定义为枚举类型。
- enum 枚举类型名
- {
- 枚举元素列表;
- }枚举类型变量名;
例如:
- enum day{
- sun,mon,tue,wed,thu,fri,sat
- }weekend,workday;
-
- //声明了一个枚举类型,数据类型名day,
- //其变量的取值范围为星期天至星期六,
- //声明时定义了两个枚举类型变量weekend和workday。
注意:
声明的枚举类型也可以没有类型名,
但如果需要使用此枚举类型的话,就必须在声明时同时定义变量。
C语言中的枚举元素是按照常量进行处理的,所以又称为枚举常量。
不能因为它们是标识符而把它们当作变量来使用,在使用时是不能对它们赋值的。
sun=0;mon=1;//错误,不能给枚举常量赋值
每一个枚举元素都代表一个整数,
C语言编译器按照定义时的顺序默认它们的值为0,1,2,3,4,5,6......
workday=mon;//相当于workday=1;
枚举常量的引用和输出:
printf("%d",sun); //输出整数0
枚举变量的引用和输出:
- workday=mon;
-
- printf("%d",workday); // 输出整数1
我们也可以人为的指定枚举元素的数值,在声明的枚举类型时指出即可。
例如:
- enum weekend{sun=7,mon=1,tue,wed,thu,fri,sat}weekend,workday;
-
- // 星期二2,星期三3,......星期六6
枚举类型可以用来进行比较和判断
- if(workday==mon){......};
-
- if(workday==sat){......};
示例:
- #include
- enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat};
-
- int main()
- {
- printf("%d %d %d %d %d %d %d\n", sun, mon, tue, wed, thu, fri, sat);
- return 0;
- }
- // 输出7 1 2 3 4 5 6
简单的枚举类型应用示例:
根据你输入的数字输出对应的星期数
- #include
- enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat}day;
-
- int main()
- {
- while (1)
- {
- scanf("%d", &day);
- switch (day)
- {
- case 7:
- printf("你输入了周日\n");
- break;
- case 6:
- printf("你输入了周六\n");
- break;
- case 5:
- printf("你输入了周五\n");
- break;
- case 4:
- printf("你输入了周四\n");
- break;
- case 3:
- printf("你输入了周三\n");
- break;
- case 2:
- printf("你输入了周二\n");
- break;
- case 1:
- printf("你输入了周一\n");
- break;
- default:
- printf("你输入了无效数字\n");
- }
- }
- return 0;
- }
_____________#