结构体(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; //error
struct 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;
} ```