C语言第七章:C语言结构体
一,什么是结构体
C语言中给我们提供了基本的数据类型,例如:int,double,char等,但是有些时候是无法满足我们的要求的,例如我们要存储一个学生整体,这个学生有姓名,身高,成绩等多个字段组成,所以我们需要一种复合的数据类型,因此C语言了结构体这个概念。
把一些基本的数据类型组合在一起,形成一个新的复合数据类型,这就叫结构体。
二,结构体的定义
结构体的定义有三种形式,但是我们只推荐使用第一种。
1.定义一个新的结构体类型(注意:必须末尾要加分号)
strutc Student { char name[100]; int age; float score; };
2.定义一个新的结构体类型,并同时定义一个变量
struct Student { char name[100]; int age; float score; }stu;
3.直接定义结构体变量,省略类型名称
struct { char name[100]; int age; float score; }stu;
4.结构体的特点:
- 结构体允许在结构体定义中定义结构体,即结构体可以包含结构体。
- 结构体所占的内存空间等于组成结构体基本类型的数据之和,例如上述第一种定义所占的单位内存为:size = 100 + 4 + 4 = 108 个字节。
- 结构体变量之间不可以进行加减乘除操作,但是结构体变量之间可以进行互相赋值的操作。
三,结构体的初始化
这里的初始化我们指用第一种方式进行定义的初始化。
结构体的初始化有两种方式:
- 在进行定义变量的同时进行初始化(注意:定义变量之后,再以下面的方式进行初始化是错误的)
# include<stdio.h> struct Student { char name[100]; int age; float socre; }; int main(void) { // 定义结构体变量的同时进行初始化 struct Student student = {"王刚",21,98};
// 以下方式是错误的
struct Student student;
student = {"王刚",21,98F};return 0; }
- 定义变量结束之后,再进行初始化
# include<stdio.h> struct Student { char name[100]; int age; float score; }; int main(void) { struct Student student; student.name = "王刚"; student.age = 21; student.score = 89; return 0; }
四,获取结构体变量的成员
获取结构体变量的成员有两种方式:
- 通过结构体变量名.成员变量名的方式获取
# include<stdio.h> struct Student { char name[100]; int age; float score; }; int main(void) { struct Student student = {"王刚",21,89}; printf("姓名:%s \n",student.name); printf("年龄:%d \n",student.age); printf("成绩:%f \n",student.score); return 0; }
- 通过指针变量名->成员变量名的方式获取
# include <stdio.h> struct Student { char name[100]; int age; float score; }; int main(void) { struct Student student = {"王刚",21,98}; // 取得该结构体变量的地址 struct Student * pStu = &student; // 获取结构体变量的成员并输出 printf("姓名:%s \n", pStu->name ); printf("年龄:%d \n", pStu->age); printf("成绩:%f \n", pStu->score); return 0; }
上面程序解释:
- pStu->name在计算机执行的过程中会解释成(*pStu).name,因为student 等价于 *pStu,所以pStu->name等价于student.name
五,结构体作为函数的形参
当结构体作为函数的形参进行传递的时候,我们这里用结构体的地址来进行操作,即形参是结构体指针,而非结构体变量。因为在进行函数传参的过程中,如果函数形参定义的是结构体变量则实际是对结构体的成员数据的一份拷贝,而非真正的引用要传递的结构体变量,但是我们使用结构体指针则是真正的地址传递。而且通过结构体指针会有传输速度快,内存消耗少的优点。
# include<stdio.h> struct Student { char name[100]; int age; float score; }; // 形参为结构体变量 void updateStudent1(struct Student stu) { stu.score = 90; } // 形参为结构体指针变量 void updateStudent2(struct Student * pStu) { pStu->score = 90; } int main(void) { struct Student stu = {"王刚",21,60}; // 调用函数修改王刚的成绩为90分 // 第一种方式 updateStudent1(stu); // 输出 printf("成绩:%f \n",stu.score); // 第二种方式 updateStudent2(&stu); // 输出 printf("成绩:%f \n",stu.score); return 0; }
结果为下图,由此可见只有通过传递结构体指针变量才可以实现结构体变量成员数据的真正修改。
六,结构体综合小应用:学生管理系统
该小程序,动态的构造了一个数组来存储结构体,注意这个动态构造结构体数组的方法和思路。
# include <stdio.h> # include <malloc.h> // 定义学生结构体 struct Student { char name[100]; int age; float score; }; // 主函数 int main(void) { // 录入学生人数 int len = 0; printf("请输入录入学生的个数:\n"); printf("len = "); scanf("%d",&len); // 动态分配结构体数组的内存,这里的内存长度=单元结构体内存长度 * 学生人数 struct Student * pArr = (struct Student *)malloc(len * sizeof(struct Student)); // 循环录入学生信息 for(int i=0;i<len;i++) { printf("请输入第%d个学生的信息:\n",i+1); printf(" name = "); scanf("%s",pArr[i].name); // name是数组名称,它本身就代表是第一个元素的地址,所以这里不加&取地址符 printf(" age = "); scanf("%d",&pArr[i].age); printf(" score = "); scanf("%f",&pArr[i].score); printf("\n"); } // 冒泡法根据成绩排序,注意这里比较的是学生的成绩,而进行交换的则是结构体变量 for(int x=0;x<len;x++) { for(int y=0;y<len-x-1;y++) { struct Student temp; int temp1 = pArr[y].score; int temp2 = pArr[y+1].score; if(temp1 < temp2) { temp = pArr[y]; pArr[y] = pArr[y+1]; pArr[y+1] = temp; } } } // 打印结果 for(int j=0;j<len;j++) { printf("=================第%d的学生信息=================\n",j+1); printf(" name = %s \n",pArr[j].name); printf(" age = %d \n",pArr[j].age); printf(" socre = %f\n",pArr[j].score); } return 0; }
运行结果为: