跳到主要内容

整体练习-学生管理系统

在学习的最后,我们为大家准备了一个比较综合的练习,这里会用到很多我们前面所学习到的知识。

1. 系统介绍

在这里,我们首先采用了数组的方式来存储我们输入的内容。同时,我们这里利用里前面学习到的 struct 来结构化存储我们的学生信息。

我们实现了基本的对于数据操作的几项功能:增、删、改、查。

也就是我们可以向这个系统中添加数据,删除数据,修改数据,还有就是查询数据。这里的查询数据,我们又分为了全部无条件的查询,和按照姓名条件的查询。

2. 功能

系统的功能里面我们设计了添加、删除、修改、列表显示和查询等 5 个功能。

添加:添加就是将数据添加到存储数据的数组中;

删除:删除就是根据指定的序列号删除特定的一条数据;

修改:修改就是根据指定的序列号来修改学生的成绩;

列表显示:列表的显示,其实就是无条件的查询,也就是在没有特点查询条件的情况下,将存储的数据全部显示出来;

查询:这里的查询,就是按照姓名这个特性的条件。把符合这个条件的数据筛选出来,并显示出来。

3. 示例程序

#include <stdio.h>
#include <string.h>

#define StudentNumbers 50
#define NameLength 50

typedef struct
{
int id;
char name[NameLength];
int age;
int score;
int flag;
} Student;

int add(Student student, Student Students[]);
int del(int id, Student students[]);
int display(Student students[]);
int update(int id, Student students[]);
int search(char name[], Student students[]);

int main()
{
int id = -1;
char name[NameLength];
int choice = 0;
int stop = 0;
Student students[StudentNumbers];
Student student;

for (int i = 0; i < StudentNumbers; i++)
{
students[i].id = i;
students[i].flag = 0;
}

while (stop == 0)
{
printf("-------------------------\n");
printf("\* 学生管理系统 \*\n");
printf("-------------------------\n");
printf("1 添加\n");
printf("2 修改成绩\n");
printf("3 查询\n");
printf("4 删除\n");
printf("5 显示学生列表\n");
printf("0 退出程序\n");
printf("请直接输入数字选项:");

scanf("%d", &choice);

switch (choice)
{
case 1:
printf("请输入学生姓名:");
scanf("%s", student.name);
printf("请输入学生的年龄:");
scanf("%d", &student.age);
printf("请输入学生成绩:");
scanf("%d", &student.score);
add(student, students);
break;
case 2:
printf("请输入要修改成绩的学生编号:");
scanf("%d", &id);
update(id, students);
break;
case 3:
printf("请输入要查找的学生姓名:");
scanf("%s", name);
search(name, students);
break;
case 4:
printf("请输入要删除的学生编号:");
scanf("%d", &id);
del(id, students);
break;
case 5:
display(students);
break;
case 0:
stop = 1;
break;

default:
printf("输入选项有误\n");
break;
}
}

return 0;
}

int add(Student student, Student students[])
{
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].flag == 0)
{
strcpy(students[i].name, student.name);
students[i].age = student.age;
students[i].score = student.score;
students[i].flag = 1;
return 0;
}
}

return 1;
}

int del(int id, Student students[])
{
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].id == id)
{
students[i].flag = 0;
return 0;
}
}
return 1;
}

int display(Student students[])
{
printf("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n");
printf("学生列表\n");
printf("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n");
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].flag == 1)
{
printf("学生编号:%d,学生姓名:%s,年龄:%d,成绩:%d\n", students[i].id, students[i].name, students[i].age, students[i].score);
}
}
printf("\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\n");
return 0;
}

int update(int id, Student students[])
{
int score = -1;
printf("请输入新的成绩:");
scanf("%d", &score);
for (int i = 0; i < StudentNumbers; i++)
{
if (students[i].id == id)
{
students[i].score = score;
return 0;
}
}

return 1;
}

int search(char name[], Student students[])
{
for (int i = 0; i < StudentNumbers; i++)
{
if (strcmp(name, students[i].name) == 0)
{
printf("学生编号: %d,学生姓名: %s,年龄: %d,成绩: %d\n", students[i].id, students[i].name, students[i].age, students[i].score);
return 0;
}
}
printf("没有查找到相关学生信息。\n");
return 1;
}

很多人可能会第一次接触这么长的程序,会产生畏惧的心理。其实不用担心。要相信自己可以看懂的。

我们分开来讲解一下。

在程序的最开始我们需要引入程序中可能需要使用的函数的头文件。这里我们因为要使用 printfscanf 等,所以需要 stdio 函数库。因为要使用 strcpystrcmp 函数,所以需要 string 函数库。

#include <stdio.h>
#include <string.h>

为了便于程序中的维护,不用在很多出修改共用的数值。所以这里定义了一个常量

#define StudentNumbers 50
#define NameLength 50

为了存储学生的信息。我们用了 struct 来定义学生的信息。里面包含学生的编号 id ,姓名 name 这是一个字符串,年龄 age ,成绩 score ,标志位 flag 这个变量是用来表示是否有学生信息存储在该位置的。不过这里我们使用了之前没有介绍的一个 typedef 。这个关键字使用的好处是使得后面使用这个 struct 的时候不用每次都用关键字 struct 来定义,只要用这个结构的名称直接定义就可以了,如同我们定义整数等内置类型一样方便。

typedef struct
{
int id;
char name[NameLength];
int age;
int score;
int flag;
} Student;

为了便于维护,我们没有按照函数出现的顺序来写。不过 C 语言一直秉承着先定义再使用的原则。所以。如果你使用的函数没有在使用前出现,而是在后面的话,那么你就需要先让编译器知道这个函数的基本情况。这个时候我们会先把函数的定义写在前面。

我们可以看到下面我们定义了这个系统的功能。每个功能我们都会写一个函数。其实不写这些函数,把所有的功能写在 main 函数内部也是可以的。但是这样会在维护上存在问题。进行测试也会变得困难。

int add(Student student, Student Students[]);
int del(int id, Student students[]);
int display(Student students[]);
int update(int id, Student students[]);
int search(char name[], Student students[]);

这里定义了一些需要使用的变量。stop 变量是用来控制程序循环的,也就是控制程序在什么时候可以结束循环的。我们定义了一个 Student 的数组,用来存储学生的信息。用一个单独的变量来存储单条的学生信息。

int id = -1;
char name[NameLength];
int choice = 0;
int stop = 0;
Student students[StudentNumbers];
Student student;

这里我们通过循环来初始化我们的数组。

for (int i = 0; i < StudentNumbers; i++)
{
students[i].id = i;
students[i].flag = 0;
}

循环语句如果在不改变条件的情况下会一直循环。确保我们的系统可以一直运行。

while (stop == 0)

在接收到输入后。我们就会通过 switch 来进行相应的匹配。完成对应的操作。这比使用大量的 if 语句简约了很多。

switch (choice)

在子程序中,也就是实现增、删、改、查这些功能程序中。我们用了循环语句来访问数组中的元素。同时,利用了判断语句与特定的变量,来判断该位置是否存有学生信息。

运行结果:

utopia@DESKTOP:~$ ./test
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:1
请输入学生姓名:张三
请输入学生的年龄:22
请输入学生成绩:100
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:1
请输入学生姓名:李四
请输入学生的年龄:21
请输入学生成绩:90
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:1
请输入学生姓名:王二
请输入学生的年龄:23
请输入学生成绩:99
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:5
******************
学生列表
******************
学生编号:0,学生姓名:张三,年龄:22,成绩:100
学生编号:1,学生姓名:李四,年龄:21,成绩:90
学生编号:2,学生姓名:王二,年龄:23,成绩:99
******************
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:2
请输入要修改成绩的学生编号:1
请输入新的成绩:80
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:5
******************
学生列表
******************
学生编号:0,学生姓名:张三,年龄:22,成绩:100
学生编号:1,学生姓名:李四,年龄:21,成绩:80
学生编号:2,学生姓名:王二,年龄:23,成绩:99
******************
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:4
请输入要删除的学生编号:1
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:5
******************
学生列表
******************
学生编号:0,学生姓名:张三,年龄:22,成绩:100
学生编号:2,学生姓名:王二,年龄:23,成绩:99
******************
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:1
请输入学生姓名:张五
请输入学生的年龄:20
请输入学生成绩:70
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:5
******************
学生列表
******************
学生编号:0,学生姓名:张三,年龄:22,成绩:100
学生编号:1,学生姓名:张五,年龄:20,成绩:70
学生编号:2,学生姓名:王二,年龄:23,成绩:99
******************
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:3
请输入要查找的学生姓名:张五
学生编号: 1,学生姓名: 张五,年龄: 20,成绩: 70
-------------------------
* 学生管理系统 *
-------------------------
1 添加
2 修改成绩
3 查询
4 删除
5 显示学生列表
0 退出程序
请直接输入数字选项:

在程序中,我们首先添加了 3 条学生的记录。然后我们进行了列表显示。接着,我们尝试修改了其中一个学生成绩,并再次查看列表,发现成绩修改生效了。然后,我们删除了一个学生,列表显示结果其已经被删除了。然后我们又尝试添加了一个学生。列表显示结果添加成功。最后我们按照姓名查找了一个学生。

4. 小结

在这里,我们知识综合利用了我们之前所学习的一部分知识来完成一个接近实际可用的系统。

当然作为一个可以使用的系统,我们还会设计到数据输入时合法性的校验,以及数据持久化的存储等等一系列的问题需要考虑。

同时在一个系统规模变大以后,其存储的结构和方式会影响到数据的操作效率,最直观的就是完成一次操作所需要的时间会发生较大甚至巨大的变化。这个时候,通过改善数据结构与算法会起到非常重大的作用。但是切记实现功能在很多时候时一个系统的第一要务,而优化系统则是在你实现一个系统以后在做的事情。有本书中写过,永远不要上来就设计一个庞大的系统。软件的设计这个时候是另外一个重要的部分。我们这里既没有考虑设计,也没有考虑算法与数据结构。只是通过我们现有的知识,来实现一个较为完整的功能。

学习没有终点,人生短暂而漫长。需要你不断的通过学习来找寻乐趣。不然这短暂的人生稍纵即逝,这漫长的人生会让你苦闷不堪。所以闲来没事,用多种方式多学习一点。尽量找点可靠的信息来源看。谢谢大家!