结构体(struct)
为什么需要结构体
什么叫结构体
把一些基本类型数据组合在一起,形成一个新的复合数据类型,这个叫结构体。
#include <stdio.h>struct Student{int age;float score;char sex;};int main(void){struct Student st = {80, 66.6, 'F'}; //struct Student为数据类型,//st为结构体变量return 0;}
定义结构体的3种方式
//第一种方式----推荐使用,只是定义了一个新的数据类型,方便定义多个变量struct Student{int age;float score;char sex;};//第二种方式----过于精简,不能重复定义struct Student2{int age;float score;char sex;}st2;//第三种方式----过于精简,不能重复定义struct{int age;float score;char sex;}st3;
结构体变量的用法
赋值和初始化
第一种方式:定义结构体变量的同时,整体赋初值struct Student st = {10, 66.6, 'F'};第二种方式:定义结构体变量后,对每个成员赋初值struct Student st;st.age = 10;st.score = 66.6;st.sex = 'F';
定义结构体指针变量并赋值
定义形式:struct 结构体名 *变量名;赋值格式:struct 结构体名 *变量名 = &结构体变量;例子:struct Student st = {10, 66.6, 'F'};//struct Student *pst = st; //errorstruct Student *pst = &st; //&符号不能少
取出结构体变量中的每个成员
#include <stdio.h>struct Student{int age;float score;char sex;};int main(void){struct Student st = {10, 33.3, 'F'};struct Student* pst = &st;//第一种取出方式st.age = 20; //结构体变量名.成员名//第二种取出方式----(更常用)pst->age = 33; //指针变量名->成员名return 0;}//Note: pst->age在计算机内部会被转换成(*pst).age,等价于st.age。
结构体变量和结构体指针变量作为函数参数传递的问题
当结构体变量作为函数的形参时:
- 对结构体变量进行修改时,必须发送结构体变量的地址;
- 对结构体变量进行打印输出时,可以发送结构体变量的地址(推荐使用,内存占用空间小,执行速度快),也可以发送变量名。
结构体变量的运算
结构体变量不能相互加减,也不能相互乘除,但可以相互赋值。
例子:struct Student{int age;char sex;char name[100];};struct Student st1,st2;// st1+st2; st1-st2; st1*st2; st1/st2; //都是错误的st1 = st2; //正确
冒泡排序
1. 确定一个数组仅需要两个参数;2. 冒泡排序的核心是先找最大值或最小值,下面代码是先找最大值。void sort(int* arr, int len){int i = j = temp = 0;for(i = 0;i < len - 1;i++) //比较总次数{for(j = 0;j < len - 1 - i;j++) //两两比较{if(arr[j] > arr[j + 1]){temp = arr[j];arr[j] = arr[j + 1];a[j + 1] = temp;}}}}
动态构造存放学生信息的结构体数组
/* 申请动态空间存入学生信息,并进行排序 */#include <stdio.h>#include <malloc.h>// 学生信息结构体struct Student{int age;float score;char name[100];};// 学生信息录入void Info_input(struct Student *pArr){int len;struct Student temp;printf("请输入学生的个数:");scanf("%d", &len);pArr = (struct Student *)malloc(len * sizeof(struct Student)); //struct占用的内存空间大小为所有结构体成员的空间总和// 信息录入for (int i = 0; i < len; i++){printf("请输入第%d个学生的信息:\n", i + 1);printf("age = ");scanf("%d", &pArr[i].age);printf("name = ");scanf("%s", pArr[i].name); //name是数组名,本身是数组的首地址,无需加“&”符号printf("score = ");scanf("%f", &pArr[i].score);}// 排序for (int i = 0; i < len - 1; i++){for (int j = 0; j < len - 1 - i; j++){if (pArr[j].score > pArr[j + 1].score){temp = pArr[j];pArr[j] = pArr[j + 1];pArr[j + 1] = temp;}}}// 输出for (int i = 0; i < len; i++){printf("\n第%d各学生的信息是:\n", i + 1);printf("age = %d\n", pArr[i].age);printf("name = %s\n", pArr[i].name);printf("age = %f\n", pArr[i].score);printf("\n");}}int main(void){struct Student *st = NULL;Info_input(st);free(st);return 0;}
枚举(enum)
枚举的定义
把一个事物所有可能的取值一一列举出来。
定义形式:enum typeName{ valueName1, valueName2, valueName3, ...... };----枚举值默认从0开始,往后逐个加1。初始化定义的时候,可以指定枚举值的数值,一般只定义第一个枚举值即可。例子:enum week{ Mon, Tues, Wed, Thurs, Fri, Sat, Sun };
枚举的用法
/* 查询星期缩写 */#include <stdio.h>enum week{Mon = 1,Tues,Wedn,Thurs,Fri,Sat,Sun};int main(void){enum week day;printf("请输入你要查询的星期缩写数值:");scanf("%d",&day);switch (day){case Mon:printf("这是Mon");break;case Tues:printf("这是Tues");break;case Wedn:printf("这是Wedn");break;case Thurs:printf("这是Thurs");break;case Fri:printf("这是Fri");break;case Sat:printf("这是Sat");break;case Sun:printf("这是Sun");break;default:printf("error,请输入整型数值!");break;}return 0;}
使用枚举的注意点
- 枚举列表中的枚举值标识符的作用范围是全局的,不能再定义同样名字的变量;
- 枚举值是常量,除了初始化定义时可以指定数值,其余情况下不可对其赋值;
- 枚举和宏其实非常类似:宏在预处理阶段将名字替换成对应的值,枚举在编译阶段将名字替换成对应的值。我们可以将枚举理解为编译阶段的宏;
- 枚举值不是变量,不占用内存空间,不能用
**&**取枚举值的地址; -
枚举的优缺点
优点:限定了取值的范围,使代码更安全;
- 缺点:书写较为麻烦。
共用体(union)
共用体的定义形式
union 共同体名{成员列表1;...成员列表n;};
创建共同体的三种方式
```c // 第一种方式(推荐使用)——定义共同体后,创建共同体变量 union data { int n; char ch; double f; }; union data a, b, c;
// 第二种方式(过于精简,不能重复定义)——定义共同体的同时,创建共同体变量 union data { int n; char ch; double f; }a, b, c; // 第三种方式(过于精简,一次性使用)——不定义创建共同体变量 union { int n; char ch; double f; }a, b, c;
<a name="zGKGf"></a>## 共同体的内存存储分布```c#include <stdio.h>union data{int n;char ch;short m;};int main(){union data a;printf("%d, %d\n", sizeof(a), sizeof(union data) );a.n = 0x40;printf("%X, %c, %hX\n", a.n, a.ch, a.m);a.ch = '9';printf("%X, %c, %hX\n", a.n, a.ch, a.m);a.m = 0x2059;printf("%X, %c, %hX\n", a.n, a.ch, a.m);a.n = 0x3E25AD54;printf("%X, %c, %hX\n", a.n, a.ch, a.m);return 0;}
结构体和共同体的区别
结构体
- 结构体的各个成员占用不同的内存,成员之间没有相互影响;
结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能存在内存缝隙)。
共同体
共同体的所有成员占用同一段内存,修改一个成员会影响其余所有成员;
- 共同体占用的内存等于最长的成员占用的内存;
- 共同体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新成员赋值,会把原来成员的值覆盖掉。
用法示例
```c / 设计一个包含共用体的结构体 /include
include
define TOTAL 4
struct memberInfo { char name[20]; int num; char sex; char profession; //作为判断选择union的变量 union S_or_C //共同体保存两个特征——二选一 { float score; char course[20]; } sc; };
int main(void) { struct memberInfo bodys[TOTAL]; //定义一个结构体变量数组,存放多个成员信息 // 输入人员信息 for (int i = 0; i < TOTAL; i++) { printf(“Input data: “); scanf(“%s %d %c %c”, bodys[i].name, &(bodys[i].num), &(bodys[i].sex), &(bodys[i].profession)); if (bodys[i].profession == ‘s’) //判断是否为学生 { scanf(“%f”, &(bodys[i].sc.score)); //输出分数信息 } else { scanf(“%s”, &(bodys[i].sc.course)); //输出课程信息 } fflush(stdin); }
//输出人员信息printf("\nName\t\tNum\tSex\tProfession\tScore / Course\n");for (int i = 0; i < TOTAL; i++){if (bodys[i].profession == 's'){ //如果是学生printf("%s\t%d\t%c\t%c\t\t%f\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.score);}else{ //如果是老师printf("%s\t%d\t%c\t%c\t\t%s\n", bodys[i].name, bodys[i].num, bodys[i].sex, bodys[i].profession, bodys[i].sc.course);}}return 0;
} ```


