郑州大学
课程设计说明书
题目: 学生信息管理系统
姓 名 : 张嘉奇
院 (系): 信息工程学院
专业班级 : 20级
学 号 : 20
指导教师 : 王礼云
成 绩:
时间: 2021 年 6月15日至 2021 年 6 月19日
郑州大学
课程设计说明书
题目: 学生信息管理系统
专业、班级20级学号20姓名张嘉奇
主要内容:
设计开发一个小型学生信息管理系统,至少具有以下功能:能实现对学生信息的批量录入、浏览、修改、删除、添加和查询功能。要求设计出的操作界面能实现数据的录入、浏览、修改、删除、查询以及退出系统。
基本要求:
1、巩固并加深学生对C语言程序设计知识的理解;
2、认识面向过程和面向对象两种设计方法的区别;
3、进一步掌握和应用VC++6.0集成开发环境;
4、提高运用C语言解决实际问题的能力;
5、初步掌握开发小型实用软件的基本方法,能独立设计、实现基本的MIS系统。
主要参考资料:
[1] 宋丽芳. C语言程序设计[M].现代教育出版社.2017.9
[2] 深入理解数据结构之链表absfree-博客园MicroSoft Development Network- MSDN 2014.2
[3] 深入理解数据结构之链表absfree-博客园MicroSoft Development Network- MSDN 2016.5
[4] 严蔚敏,吴伟民.数据结构(C语言版)[M]. 北京:清华大学出版社,2007.4
[5] 明日科技. C语言从入门到精通(第3版)[M]. 北京:清华大学出版社.2017.2
完 成 期 限: 2021.6.15-2021.6.19
指 导 教师签名:
课程负责人签名:
目 录
1 需求分析
1.1 系统概述
此次期末C语言设计的程序题目是:学生信息管理系统。
本系统主要用于管理学生各种信息,如各课考试成绩,学生基本信息等。且提供了较为丰富的人机交互界面,让用户在使用等待的同时不会觉得枯燥。同时也具备方便的后台增删、修改、查看功能。使用户和管理员能更好的录入和管理信息,可以在很大程度上满足用户的使用需求。
1.2 系统运行环境
处理器: Inter Pentium 166 MX 或更高
内存: 32M
硬盘空间:1GB
显卡: SVGA显示适配器
2. 软件环境
操作系统:Windows 98/ME/2000/XP 或更高
开发语言:Visual C++/DEV C++
1.3 功能需求描述
学生信息管理系统主要是以方便、简单、快捷的方式对用户信息进行管理(增删、修改);同时设计了添加美观的加载条供用户进行实时观察。
学生信息管理系统主要需要实现以下一些基本功能:
1. 录入:向系统中录入学生信息;
2. 增添:向系统中增加学生信息;
3. 查询:查询系统中的学生信息;
4. 修改:修改系统中已有的学生信息;
5. 删除:删除系统中已有的学生信息;
6.读取:从文件中读取学生信息数据;
2 概要设计
2.1 开发与设计的总体思想
现在各个大学都面临着对众多学生成绩管理的需求。本系统设计开发的基本目的是为了帮助大学中的教师管理学生的成绩,方便整理,排序,查询信息。
2.2 系统模块结构
依据需求分析结果,投票系统可以分为五个模块,录入模块;查询模块;增添模块;删除修改模块;保存模块。如图2-1所示:
图2-1 系统模块结构图
1. 查询模块
查询模块主要实现的功能是根据用户输入的信息在链表中进行查找。
2. 录入模块
提示用户输入信息,并将其保存到内存中。
4. 删除修改模块
修改或删除系统中已有的学生信息。
- 读取功能
从文件中读取已保存的数据库文件,并写入内存
- 保存功能
程序流程首先是开始,接着输入x,然后分别输入x=1,x=2,x=3,x=0;x=1对应的是查询模块,输入t,t=1对应学号查询,t=2对应姓名查询,t=3对应年龄查询;x=2对应录入模块;x=3对应修改模块,输入choose,Y或y对应修改信息,N或n对应不做修改,D对应删除信息;x=0对应退出系统,接着保存返回原来流程;如下图2-2所示。
3详细设计与实现
基于系统需求分析与系统总体设计的结论,下面按照模块的划分来分别阐述系统的详细设计和实现过程。
3.1 数据类型
本系统中主要采用结构数据类型存储学生的基本信息。本系统中定义strStuinfo结构体类型用于描述学生信息,strStuinfo结构体类型定义格式如下图,定义strScore为学生成绩结构体和一些基础信息,部分代码如下:
struct strStuInfo { //存储数据的结构体
int num; //学号
char name[32]; //姓名
char gender[8]; //性别
int age; //年龄
struct strScore { //成绩
float math; //高数
float english; //英语
float clang; //C 语言
float pe; //体育
float politics; //马哲毛概
float total; //总分
} score;
char address[128]; //住址
struct strStuInfo *before; //链表前指针
struct strStuInfo *next; //链表后指针
} headStuInfo = { 0, "0", "0", 0, {0, 0, 0, 0, 0}, "0", NULL, NULL };
其中:num:学号;name:姓名;gender:性别;age:年龄;address:住址;strStuInfo *before:指向链表前指针;strStuInfo *next:指向链表后指针。headStuinfo:表示链表格式。
strScore数据结构体主要设置成绩分数定义格式如下:
struct strScore { //成绩
float math; //高数
float english; //英语
float clang; //C 语言
float pe; //体育
float politics; //马哲毛概
float total; //总分
} score;
math:高数;english:英语;clang:C语言;pe:体育;politics:马哲毛概;
total:总分。
查询功能模块主要实现查询学生各个信息的功能。该模块按照查询方法不同分为学号,姓名,年龄查询模块。
void inquireStuInfo() { //信息查询模块,集成功能
int i, t, num, age;
char name[32];
struct strStuInfo *searchPtr = NULL;
do {
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "欢迎使用学生信息管理系统");
putchar('\n');
displayBlock(CMDWIDTH, "----------------------------");
displayBlock(CMDWIDTH, "------------");
displayBlock(CMDWIDTH, "信息查询菜单");
displayBlock(CMDWIDTH, "------------");
displayBlock(CMDWIDTH, "1. 根据学号查找");
displayBlock(CMDWIDTH, "2. 根据姓名查找");
displayBlock(CMDWIDTH, "3. 根据年龄查找");
displayBlock(CMDWIDTH, "4. 显示所有信息");
displayBlock(CMDWIDTH, "0. 返回程序菜单");
displayBlock(CMDWIDTH, "----------------------------");
} while (t != 0);
inquireStuInfo:查询模块选择方式函数名。
searchPtr:指向结构体。
整型i表示查询到的相同年龄的总人数。
整型t表示表选方式前的数字(如1对应根据学号查询)
age表示年龄。
- 查询模块子模块中的学号查询流程图:
学号查询子模块结束后,判断searchptr->num是num,如果是的话是使用printSntifo函数将信息输出,若不是的话,判断searchptr->next是NULL是的话,模块结束,如国不是的话提示用户信息未找到,检查是否出错,如图3-1所示。
查询模块子模块中的学号查询代码如下:
printf("请输入学号:");
scanf("%d", &num);
CLEARSTDIN;
for (searchPtr = &headStuInfo; ; searchPtr = searchPtr->next) {
if (searchPtr->num == num) {
setWindow(CMDWIDTH * 2, CMDHEIGHT);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
putchar('\n');
printf("学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\t地址\n");
printStuInfo(searchPtr);
printf("\n请按任意键返回查询菜单...");
getch();
break; }
else if (searchPtr->next == NULL) {
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "未找到该学号,请检查输入是否有误。");
Sleep(2000);
break; }}
使用for循环进行对链表的遍历如果学号存在,则使用输出函数printStuinfo输出相关信息,如果不存在则提示用户检查是否有误。利用指针遍历链表,并分别对其中的数据进行比对,若找到与之相匹配的则会显示信息,否则提示未找到,提示用户检查是否有误。
查询模块子模块中的姓名查询流程图:
姓名查询子模块开始,接下来输出strcmp(searchPtr->name,name)是0,是的话使用printSntifo函数将信息输出;若不是用searchptr->next是NULL,是的话提示用户未找到信息,若不是信息查询模块结束,如图3-2所示。
查询模块子模块中的姓名查询代码如下:
printf("请输入姓名:");
scanf("%s", &name);
CLEARSTDIN;
for (searchPtr = &headStuInfo; ; searchPtr = searchPtr->next) {
if (strcmp(searchPtr->name, name) == 0) {
setWindow(CMDWIDTH * 2, CMDHEIGHT);
setWindow(CMDWIDTH * 2, CMDHEIGHT);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
putchar('\n');
printf("学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\t地址\n");
printStuInfo(searchPtr);
printf("\n请按任意键返回查询菜单...");
getch();
break; }
else if (searchPtr->next == NULL) {
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "未找到该姓名,请检查输入是否有误。");
Sleep(2000);
break;}}
同样使用for循环对链表进行遍历,输入姓名,然后使用strcmp函数对两个字符串进行对比,如果相等则输出相应的信息。如果为空则提示用户检查是否有误。
- 查询模块子模块中的年龄查询流程图:
年龄查询子模块,首先搜索seachPtr是NULL,是的话看i==0,是0则为未找到用户,若不是则输出同年龄的总个数,然后年龄车查询模块结束;seachPtr是NULL不是的话,seachPtr->age是age?是的话用printStuinfo函数输出信息,且i++,年龄查询模块结束,如图3-3所示。
查询模块子模块中的年龄查询代码如下:
printf("请输入年龄:");
scanf("%d", &age);
CLEARSTDIN;
setWindow(CMDWIDTH * 2, CMDHEIGHT);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
putchar('\n');
printf("学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\t地址\n");
for (searchPtr = &headStuInfo, i = 0; ; searchPtr = searchPtr->next) {
if (searchPtr == NULL) {
if (i == 0) {
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "未找到该年龄,请检查输入是否有误。");
Sleep(2000);
break; }
else {
printf("共有%d名%d岁的学生。\n", i, age);
printf("\n请按任意键返回查询菜单。");
getch();
break; }}
else if (searchPtr->age == age) {
printStuInfo(searchPtr);
i++;}
因为年龄元素容易出现重复的情况,所以使用i表示存在人数,for循环进行对链表的遍历,如果存在则输出对应信息,并且i自增1标志着总人数的增加,直到searchptr为空且i!=0时输出该年龄的用户的总人数。
输入学号,系统代码运行结果如下图3-5截图:
3.3增添功能
实现方式: 遍历链表,将指针指向末项,调用输入函数 enterStuInfo 为新增数据开辟新内存并链接至链表中,最后进行用户录入操作,实际上也就是录入模块的调用。部分代码如图所示:
void entryStuInfo() { //信息录入模块,集成功能
struct strStuInfo *entryPtr = NULL;
displayBlock(CMDWIDTH, "------------");
displayBlock(CMDWIDTH, "信息录入菜单");
displayBlock(CMDWIDTH, "------------");
for (entryPtr = &headStuInfo; entryPtr->next != NULL; entryPtr = entryPtr->next);
entryPtr->next = malloc(sizeof(stru8ct strStuInfo));
enterStuInfo(entryPtr->next);
entryPtr->next->before = entryPtr;
entryPtr = entryPtr->next;
entryPtr->next = NULL;
setWindow(CMDWIDTH * 2, CMDHEIGHT);
printf("\n\n学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\t地址\n");
printStuInfo(entryPtr);
printf("\n信息录入完毕,按任意键返回主菜单。\n");
getch();}
entryStuinfo:是录入模块也是增添功能的函数名。
entryPtr:指向结构体。
sizeof函数:返回一个需要的内存块数。
malloc函数:用来分配长度为n的内存块。
在for循环中先让entryPtr指向链表,循环条件为链表的下一个元素不为空,循环语句为entryPtr指向链表中下一个元素的地址。其中运用malloc和sizeof函数对元素所需内存进行提供便于数据保存在内存中,当entryPtr指向的下一个元素为空时,则表明遍历结束,数据全部保存在内存中,此时再使用输出函数printStuinfo进行输出,让用户对比,最终提示信息(录入)增添完毕。
增添功能模块实现截图3-6所示
实现方式: 提示用户输入,并向传入参数(结构体指针)所指向的地址中写入信息。代码如下:
void enterStuInfo(struct strStuInfo *ptr) { //信息输入模块,需要外部调用
inputTip(1, 10);
printf("请输入学号:");
scanf("%d", &(ptr->num));
CLEARSTDIN;
inputTip(2, 10);
printf("请输入姓名:");
scanf("%s", &(ptr->name));
CLEARSTDIN;
inputTip(3, 10);
printf("请输入性别:");
scanf("%s", &(ptr->gender));
CLEARSTDIN;
inputTip(4, 10);
printf("请输入年龄:");
scanf("%d", &(ptr->age));
CLEARSTDIN;
inputTip(5, 10);
printf("请输入数学成绩:");
scanf("%f", &(ptr->score.math));
CLEARSTDIN;
inputTip(6, 10);
printf("请输入英语成绩:");
scanf("%f", &(ptr->score.english));
CLEARSTDIN;
inputTip(7, 10);
printf("请输入编程成绩:");
scanf("%f", &(ptr->score.clang));
CLEARSTDIN;
inputTip(8, 10);
printf("请输入体育成绩:");
scanf("%f", &(ptr->score.pe));
CLEARSTDIN;
inputTip(9, 10);
printf("请输入马哲成绩:");
scanf("%f", &(ptr->score.politics));
ptr->score.total = ptr->score.math + ptr->score.english + ptr->score.clang + ptr->score.pe + ptr->score.politics;
CLEARSTDIN;
inputTip(10, 10);
printf("请输入家庭住址:");
scanf("%s", &(ptr->address));
CLEARSTDIN; }
ptr:指向结构体。
inputTip:为输入的数据排序,用法为inputTip(该元素位次,总位次)。
输入模块的功能实现主要是运用了增添函数entryPtr,结合scanf函数和inputTip函提示用户输入,并向传入参数(结构体指针)所指向的地址中写入信息。数据保存到内存中。
输入界面截图:
3.5修改模块
根据用户输入的学号及姓名进行查询,若用户信息存在,则提示用户根据Y,N,D三种对应不同的操作进行相应行为。代码如下:
void modifyStuInfo() { //信息修改功能,集成模块
int num;
char name[32], choose;
struct strStuInfo *modifyPtr = NULL;
displayBlock(CMDWIDTH, "----------------------------");
displayBlock(CMDWIDTH, "------------");
displayBlock(CMDWIDTH, "信息修改菜单");
displayBlock(CMDWIDTH, "------------");
printf("请输入学号:");
scanf("%d", &num);
CLEARSTDIN;
printf("请输入姓名:");
scanf("%s", name);
CLEARSTDIN;
printf("\n----------------------------\n");
modifyPtr = searchStuInfo(name, num);
if (modifyPtr == NULL) {
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息查找结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "未找到该学生信息,请检查输入是否有误。");}
else {
setWindow(CMDWIDTH * 2, CMDHEIGHT);
printf("找到如下信息:\n");
printf("学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\t地址\n");
printStuInfo(modifyPtr);
printf("请按\'Y\'或\'N\'确认修改,或按\'D\'删除该信息:\040");
do {
printf("\b");
choose = getche();
} while ((choose != 'Y') && (choose != 'y') && (choose != 'N') && (choose != 'n') && (choose != 'D') && (choose != 'd'));
printf("\n-------------------------\n");
if ((choose == 'Y') || (choose == 'y')) {
enterStuInfo(modifyPtr);
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息修改结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "信息修改完成,即将返回主菜单。");
//printf("学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\t 地址\n");
//printStuInfo(modifyPtr); }
else if ((choose == 'D') || (choose == 'd')) {
modifyPtr->before->next = modifyPtr->next;
if(modifyPtr->next != NULL) modifyPtr->next->before = modifyPtr->before;
free(modifyPtr);
modifyPtr = NULL;
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息修改结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "信息删除完毕,即将返回主菜单。");}
else {
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息修改结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "信息未进行修改,即将返回主菜单。"); } }
Sleep(2000); }
modifyStuinfo:修改模块函数名。
modifyPtr:指向结构体strStuInfo。
num:定义的整型变量用来储存学号。
name:字符类型数组用来储存姓名。
printStuInfo:用于输出信息的函数。
先让modifyPtr获取链表所指向成员的学号和姓名地址,如果所指地址对应的值为空,则提示用户检查是否有误,若存在用户信息则提示用户输入Y,y;N,n;D。进行不同的操作,分为三个子模块:
- 输入Y,y:确认修改子模块。
- 输入N,n:取消修改子模块。
- 输入D:删除信息子模块。
- 修改模块流程图:
修改删除模块开始,输入num,name;接着modifyPtr是NULL?是的话信息未找到,提示用户将检查是否有误,没有结束返回主菜单;如果开始seachPtr是NULL,输入choose,然后操作,如图3-9所示。
2.确认修改子模块流程图
首先确认修改子模块开始,接着执行修改模块函数:modifyStuInfo,判断modifyptr是不是NULL,是的话,未找到,提示用户检查是否有误,然后确认修改子模块结束;如果不是的话,(choose==‘y’)||(choose==’y’),使用enterStuinfo函数将信息重新录入输入,确认修改子模块结束。如图3-10所示。
修改模块中确认修改子模块代码如下:
enterStuInfo(modifyPtr);
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息修改结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "信息修改完成,即将返回主菜单。");
//printf("学号\t姓名\t性别\t年龄\t数学\t英语\t编程\t体育\t马哲\t总分\ t地 址\n");
//printStuInfo(modifyPtr)
enterStuinfo函数:录入用户信息。
5.删除信息模块子模块流程图:
首先确认修改子模块开始,接着执行修改模块函数:modifyStuInfo,判断modifyptr是不是NULL,是的话,未找到,提示用户检查是否有误,然后确认修改子模块结束;如果不是的话,(choose==’D’)||(choose==’d’),使用if循环和链表元素的覆盖逐一删除链表成员,使用free函数进行对内存的释放,确认修改子模块结束。如图3-11所示。
modifyPtr->before->next = modifyPtr->next;
if(modifyPtr->next != NULL) modifyPtr->next->before = modifyPtr->before;
free(modifyPtr);
modifyPtr = NULL;
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息修改结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "信息删除完毕,即将返回主菜单。");
free函数:释放内存。
使用if循环和链表元素的覆盖逐一删除链表成员,使用free函数进行对内存的释放。
修改模块不作修改子模块:
代码如下:
setWindow(CMDWIDTH, CMDHEIGHT / 2);
putchar('\n');
displayBlock(CMDWIDTH, "信息修改结果");
printf("\n\n\n");
displayBlock(CMDWIDTH, "信息未进行修改,即将返回主菜单。");
提示用户不作任何修改。
- 修改模块确认修改子模块实现截图:
6.修改模块删除信息子模块实现截图:
3.6读取功能
参数传入文件名,使用fopen函数打开该文件,并利用文件操作函数逐行读取文件内容,将其中信息写入内存,构成链表。
首先检查是否存在文件,若没有则先创建新数据库文件。再检查是否为空数据文件,如不是,则开始逐行读取文件信息,并保存到内存中。若是则只进行打开文件操作,但文件为空。
代码如下:
int fileLoad(char *fileName) { //数据读取模块
int total = 0, i = 0;
FILE *filePtr = NULL;
struct strStuInfo *ptr = &headStuInfo;
if ((filePtr = fopen(fileName, "rt+")) == NULL) {
filePtr = fopen(fileName, "wt+");
displayProgress(0, CMDWIDTH - 2, CMDWIDTH - 2); //从0到100
return fclose(filePtr); } //返回值为0:创建新数据库文件
if (fgetc(filePtr) != EOF) { //检测是否为空数据库文件
rewind(filePtr); //重置文件指针
//fscanf(filePtr, "%d", &total); //获取信息总数
fscanf(filePtr, "%d\t%s\t%s\t%d\t", &total, &(ptr->name), &(ptr->gender), &(ptr->age));
fscanf(filePtr,"%f\t%f\t%f\t%f\t%f\t%f\t",&(ptr->score.math), &(ptr->score.english),&(ptr->score.clang),&(ptr->score.pe), &(ptr->score.politics), &(ptr->score.total));
fscanf(filePtr, "%s\n", &(ptr->address));
if (total == 0) displayProgress(0, CMDWIDTH - 2, CMDWIDTH - 2);
else {
while (!feof(filePtr)) { //读取文件信息,并保存到内存中
ptr->next = (struct strStuInfo*)malloc(sizeof(struct strStuInfo));
ptr->next->before = ptr;
ptr->next->next = NULL;
ptr = ptr->next;
fscanf(filePtr, "%d\t%s\t%s\t%d\t", &(ptr->num), &(ptr->name), &(ptr->gender), &(ptr->age));
fscanf(filePtr,"%f\t%f\t%f\t%f\t%f\t%f\t",&(ptr->score.math), &(ptr->score.english),&(ptr->score.clang),&(ptr->score.pe), &(ptr->score.politics), &(ptr->score.total));
fscanf(filePtr, "%s\n", &(ptr->address));
/*if (total == 0) displayProgress(0, CMDWIDTH - 2, CMDWIDTH - 2);
else displayProgress((float) (i - 1) / total * (CMDWIDTH - 2), (float) (++i) / total * (CMDWIDTH - 2), CMDWIDTH - 2);*/
displayProgress((float) (i - 1) / total * (CMDWIDTH - 2), (float) (++i) / total * (CMDWIDTH - 2), CMDWIDTH - 2); }}
return fclose(filePtr) + 1; } //返回值为1:成功打开文件,并成功读取信息
else {
displayProgress(0, CMDWIDTH - 2, CMDWIDTH - 2);
return fclose(filePtr) + 2; }} //返回值为2:成功打开文件,但文件为空
3.7保存功能
利用循环遍历链表,统计信息条数,并将其中信息写入文件。
代码:
//向参数 fileName 指定的文件中保存数据
int fileSave(char *fileName) { //数据保存模块
int total = 0, i = 0;
FILE *filePtr = NULL;
struct strStuInfo *ptr = &headStuInfo;
filePtr = fopen(fileName, "wt+"); //警告类型,无法读取原有数据库文件
for (total = 0; ptr->next != NULL; ptr = ptr->next) total++; //统计信息总数
if ((headStuInfo.num = total) == 0) {
fprintf(filePtr, "%d\t%s\t%s\t%d\t", ptr->num, ptr->name, ptr->gender, ptr->age);
fprintf(filePtr, "%f\t%f\t%f\t%f\t%f\t%f\t", ptr->score.math, ptr->score.english, ptr->score.clang, ptr->score.pe, ptr->score.politics, ptr->score.total);
fprintf(filePtr, "%s\n", ptr->address);
displayProgress(0, CMDWIDTH - 2, CMDWIDTH - 2); }
else {
for (i = 0, ptr = &headStuInfo; ptr != NULL; i++, ptr = ptr->next) { //写入信息
fprintf(filePtr, "%d\t%s\t%s\t%d\t", ptr->num, ptr->name, ptr->gender, ptr->age);
fprintf(filePtr, "%f\t%f\t%f\t%f\t%f\t%f\t", ptr->score.math, ptr->score.english, ptr->score.clang, ptr->score.pe, ptr->score.politics, ptr->score.total);
fprintf(filePtr, "%s\n", ptr->address);
displayProgress((float) (i - 1) / total * (CMDWIDTH - 2), (float) i / total * (CMDWIDTH - 2), CMDWIDTH - 2); }}
return fclose(filePtr); } //返回值为0:成功写入信息
4 系统测试
对于软件测试而言,黑盒测试是把程序看成一个黑盒子,完全不考虑程序的内部结构和处理过程。也就是说,黑盒测试是在程序接口进行的测试,它只检查程序功能是否能按照规格说明书的规定正常使用,程序是否能适当地接收输入数据产生正确的输出信息,并且保持外部信息(如:数据库或文件)的完整性。黑盒测试又成为功能测试。而白盒测试法的前提是可以把程序看成装在一个透明的白盒子里也就是完全了解程序的结构和处理过程。这种方法按照程序内部的逻辑测试程序,检验程序中的每条通路是否都能按预定的要求正确工作。白盒测试又称为结构测试。在设计得好的软件系统中,每个模块完成一个清晰定义的子功能,而且这个子功能和同其他模块的功能之间没有相互依赖关系。因此,可以把每个模块作为一个单独的实体来测试,而且通常比较容易设计检验模块正确性的测试方案。模块测试的目的是保证每一个模块作为一个单元能正确运行。
程序总模块如图4-0所示
4.1查询模块测试
1.输入确实存在的学号,输出结果截图:
4.2输入不存在的学号,输出结果截图:
4.3修改模块测试
输入确实存在的学号,输出结果截图:
总 结
我们组在这次实训中完成了学习信息管理系统,总体有录入,增添,修改,删除,保存等功能模块。实现了:信息的录入,修改,删除以及对文件中信息的保存和读取。每个模块的实现都可以说不轻松,与但学到了很多书本上所没有的知识,增进了同学之间的友谊,收获颇多。
刚刚着手系统的时候十分艰难,无从下手,很多功能无法实现,漏洞百出。 比如:链表和结构体的创建;链表是我们接触不多的知识,但确是实现代码功能的重要知识,较为困难,但我们通过查阅资料和阅读课本,实践多次创建了完整有序的链表。编写查询模块时if-else语句的嵌套总是出错;我们通过画流程图,逐一测试后能编写出完整的循环嵌套语句了。还有根据代码画出流程图,总是漏画或者出错;我们则逐行分析代码逐行画出流程图。文件读取和保存功能是没有了解过的,简单看看了解了一下并没有过多深入的研究。总的来说这次项目的问题很多,但我们没有放弃,知道了我们的不足和应该注意的地方,为下次实现学到了宝贵的经验。
短短的几天时间让我对 C 语言有了一个全新的概念,它不仅是一门课程,更是一门技术,虽然在上个学期中,我们已经学习了《C语言程序设计》这门课,但是我所学的知识最多也就是在做作业的时候才会用到,平时没有什么练习的机会,这次的课程设计是我第一次通过 自己构思,和同学讨论并且不断查阅资料来设计一项程序。这次设计,不仅巩固了我以前所学的知识,还让我对c语言有了更深一步的了解掌握了更多的技巧和技能。
参考文献
[1] 宋丽芳. C语言程序设计[M].现代教育出版社.2017.9
[2] 深入理解数据结构之链表absfree-博客园MicroSoft Development Network- MSDN 2014.2
[3] 深入理解数据结构之链表absfree-博客园MicroSoft Development Network- MSDN 2016.5
[4] 严蔚敏,吴伟民.数据结构(C语言版)[M]. 北京:清华大学出版社, 2007.4
[5] 明日科技. C语言从入门到精通(第3版)[M]. 北京:清华大学出版社.2017.2
课程设计评定表
评定项目 | 内 容 | 满分 | 评分 | 总分 |
学习态度 | 学习认真,态度端正,遵守纪律。 | 10 | ||
设计情况 | 认真查阅资料,勤学好问,提出的问题有一定的深度,分析解决问题的能力较强。 | 40 | ||
说明书质量 | 设计方案正确、表达清楚;设计思路、实验(论证)方法科学合理;达到课程设计任务书规定的要求;图、表、文字表达准确规范,上交及时。 | 40 | ||
回答问题情况 | 回答问题准确,基本概念清楚,有理有据,有一定深度。 | 10 | ||
总成绩 | 采用五级分制:优、良、中、及格、不及格 | |||
指导教师评语: 签名: 年 月 日 |
附 录
——全部代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <string.h>
typedef struct Student
{
char name[100]; //姓名
char num[100]; //学号
char sex;//性别 (w代表女生m代表男生)
int age;//年龄
int score;//成绩
}stu;
typedef struct LNode
{
stu data;
struct LNode *next;
}LinkList;
char nam[100];//名字
char nu[100];//学号
char s;//性别
int ag;//年龄
int sc;//成绩
void welocome()//登陆界面
{
// system("color b1");
printf("````````````````````````````````````````````````````````````````````````````````");
printf("\n");
printf("\n");
printf("\n");
printf(" *********************** 欢迎登录学生信息管理平台 ************************* \n");
printf("\n");
printf("\n");
printf("\n");
printf("````````````````````````````````````````````````````````````````````````````````");
}
void menu()//功能菜单
{
// system("color e3");
printf(" |________________________________________________|\n");
printf(" | |\n");
printf(" | 学生信息管理系统 |\n");
printf(" | |\n");
printf(" | 0、退出系统 |\n");
printf(" | 1、增加学生信息 |\n");
printf(" | 2、删除学生信息 |\n");
printf(" | 3、修改学生信息 |\n");
printf(" | 4、查找学生的信息 |\n");
printf(" | 5、按照学生成绩排序 |\n");
printf(" | 6、浏览全部学生信息 |\n");
printf(" | 7、保存学生信息到文件 |\n");
printf(" | |\n");
printf(" |________________________________________________|\n");
return ;
}
void InitList( LinkList *&L)//初始化链表
{
L=(LinkList *)malloc(sizeof(LinkList));
L->next=NULL;
}
void ListInsert(LinkList *&L,LinkList *p)//插入新的节点
{
LinkList *q=NULL;
q=L;
p->next=q->next;
q->next=p;
}
void addstu(LinkList *&L)//增加新的学生
{
system("color f2");
printf("请输入学生的信息:\n");
printf("学号:");
scanf("%s",nu);
LinkList *q=L->next;
while(q!=NULL )
{
if(strcmp(q->data.num,nu)==0)//判断是否存在
{
printf("该生已存在\n");
break;
}
q=q->next;
}
if(q==NULL)
{
LinkList *p;
InitList(p);
strcpy(p->data.num,nu);
printf("姓名:") ;
scanf("%s",nam) ;
strcpy(p->data.name,nam);
printf("性别:(w为男 m为女)");
scanf(" %c",&s);
p->data.sex=s;
printf("年龄:");
scanf("%d",&ag);
p->data.age=ag;
printf("总成绩:");
scanf("%d",&sc);
while(sc>100||sc<0){
printf("输入有误,请重新输入\n");
scanf("%d",&sc);
}
p->data.score=sc;
ListInsert(L,p);
}
}
void deletestu(LinkList *L)//删除学生
{
// system("color f4");
system("color f2");
printf("请输入您要删除的学生的学号:");
scanf("%s",nu);
//判断
LinkList *p,*pre;
if(L->next==NULL)
{
printf("还没有学生信息,请增加学生信息\n");
return;
}
pre=L;
p=pre->next;
int judge=0;
while(p)
{
if(strcmp(p->data.num,nu)==0)
{
judge=1;
pre->next =p->next;
free(p);
printf("删除学生成功\n");
break;
}
pre=p;
p=p->next;
}
if(judge==0)
printf("该生不存在\n");
}
void changestu(LinkList *L)//改变学生信息
{
int judge=1;
// system("color e4");
system("color f2");
printf("请输入您要修改学生的学号:\n");
scanf("%s",nu);
LinkList *q=L->next;
while(q!=NULL )
{
if(strcmp(q->data.num,nu)==0)
{
judge=1;
printf("请输入您要修改的信息选项:1.姓名 2. 总成绩 3.年龄 \n");
int n;
scanf("%d",&n);
switch(n)
{
case 1:
printf("请输入您要修改的名字:");
scanf("%s",nam);
printf("修改的名字为:%s\n",nam);
strcpy(q->data.name,nam);
printf("修改名字成功!\n");
break;
case 2:
printf("请输入您要修改的总成绩");
scanf("%d",&sc);
printf("修改的总成绩为:%d\n",sc);
q->data.score=sc;
printf("修改总成绩成功!\n");
break;
case 3:
printf("请输入您要修改的年龄:");
scanf("%d",&ag);
printf("修改的年龄为:%d\n",ag);
q->data.age=ag;
printf("修改年龄成功!\n");
break;
default :
printf("请输入正确的选项\n");
break;
}
}
q=q->next;
}
if(judge==0)
{
printf("该生不存在\n");
}
}
void findstu(LinkList *L)//按学号或者姓名查找学生并输出该生信息
{
int flag;
// system("color b1");
system("color f2");
printf("1.按学号查询:\n");
printf("2.按姓名查询:\n");
printf("请输入查询方式:");
scanf("%d",&flag);
if(flag==1){
printf("请输入该生学号:");
scanf("%s",nu);
//判断
LinkList *q=L->next;
while(q!=NULL )
{
if(strcmp(q->data.num,nu)==0)
{
printf("姓名:%s\n",q->data.name);
printf("学号:%s\n",q->data.num);
printf("性别:%c\n",q->data.sex);
printf("年龄:%d\n",q->data.age);
printf("总成绩:%d\n",q->data.score);
break;
}
q=q->next;
}
if(q==NULL)
printf("该生不存在\n");
}else{
printf("请输入该生姓名:");
scanf("%s",nam);
LinkList *q=L->next;
while(q!=NULL )
{
if(strcmp(q->data.name,nam)==0)
{
printf("姓名:%s\n",q->data.name);
printf("学号:%s\n",q->data.num);
printf("性别:%c\n",q->data.sex);
printf("年龄:%d\n",q->data.age);
printf("总成绩:%d\n",q->data.score);
break;
}
q=q->next;
}
if(q==NULL)
printf("该生不存在\n");
}
}
void display(LinkList *&L)//浏览全部学生信息
{
LinkList *q=L->next;
if(q==NULL)
{
printf("还没有学生信息,请增加学生信息\n");
return;
}
while(q)
{
// system("color c0");
system("color f2");
printf(" 学号:%s 名字:%s 年龄:%d 性别:%c 总成绩:%d \n",q->data.num,q->data.name,q->data.age,q->data.sex,
q->data.score);
q=q->next;
}
}
void paixu(LinkList *L)//按成绩排序排序 并输出排序后的结果
{
// system("color f9");
system("color f2");
LinkList *q,*p,*r=L->next;
//判断
if(r==NULL)
{
printf("还没有学生信息,请增加学生信息\n");
return;
}
while(r) //两层循环完成排序
{
p=r;
q=r->next;
LinkList *tmp;//用于排序时暂存节点
InitList(tmp);
while(q)
{
if(q->data.score > p->data.score)
{
/*先复制q结点信息到tmp*/
strcpy(tmp->data.num,q->data.num);
strcpy(tmp->data.name,q->data.name);
tmp->data.sex=q->data.sex;
tmp->data.age=q->data.age;
tmp->data.score=q->data.score;
/*再复制p结点信息到q*/
strcpy(q->data.num,p->data.num);
strcpy(q->data.name,p->data.name);
q->data.sex=p->data.sex;
q->data.age=p->data.age;
q->data.score=p->data.score;
/*最后复制exchange结点信息到p*/
strcpy(p->data.num,tmp->data.num);
strcpy(p->data.name,tmp->data.name);
p->data.sex=tmp->data.sex;
p->data.age=tmp->data.age;
p->data.score=tmp->data.score;
}
q=q->next;
}
r=r->next;
}
printf("排序后的学生信息是:\n");
display(L);
}
void saveStuDentFile(LinkList * &L)//保存学生信息到文件
{
FILE *fp;
LinkList *p=L->next;
if((fp=fopen("student.txt","w"))==NULL)// 以可写的方式打开当前目录下的.txt
{
printf("不能打开此文件,请按任意键退出\n");
exit(1);
}
while(p)
{
fprintf(fp,"%s %s %c %d %d \n",p->data.num,p->data.name,p->data.sex,p->data.age,p->data.score);
p=p->next;
printf("保存成功\n");
}
fclose(fp);
}
void readStuDentput (LinkList *&L) //运行前把文件内容读取到电脑内存
{
FILE *fp;
fp=fopen("student.txt","rb"); //以只读方式打开当前目录下的.txt
if(fp==NULL)
{
printf("不存在打开文件\n");
exit(0); //终止程序
}
int i=0;
while(!feof(fp))
{
char nu[100];//学号
char nam[100];//名字
char s;//性别
int ag;//年龄
int sc;//成绩
fscanf(fp," %s %s %c %d %d",nu,nam,&s,&ag,&sc);
i++;
}
fclose(fp);
FILE *FP;
FP=fopen("student.txt","rb"); //以只读方式打开当前目录下的.txt
if(FP==NULL)
{
printf("无法打开文件\n");
exit(0); //终止程序
}
int b=i-1;
int j=1;
while(!feof(FP))
{
fscanf(FP,"%s %s %c %d %d",nu,nam,&s,&ag,&sc);
LinkList *n=(LinkList *)malloc(sizeof(LinkList));
strcpy(n->data.num,nu);//把后者的内容拷贝到前者中
strcpy(n->data.name,nam);//把后者的内容拷贝到前者中
n->data.sex=s;
n->data.age=ag;
n->data.score=sc;
ListInsert(L,n);//插入新的节点
n=n->next;
if(j==b)
break;
j++;
}
fclose(FP); //关闭文件
}
int main()
{
system("cls");//清屏
// welocome();//登陆界面
// Sleep(3000);//延缓3秒
LinkList *L;
InitList(L);
// readStuDentput (L);//运行前把文件内容读取到电脑
int a;
int choose;
while(1)
{
printf("请输入您要选择的功能键:\n");
menu();//功能菜单
scanf("%d",&choose);
switch(choose)
{
case 0://退出
printf("谢谢使用!欢迎下次光临");
exit(0);
case 1://增加学生信息
addstu(L);//增加新的学生
break;
case 2://删除所有学生信息
deletestu(L);//删除学生
break;
case 3://改变个学生的信息
changestu(L);//改变学生信息
break;
case 4://查找某个学生的信息
findstu(L);//按学号查找学生并输出该生信息
break;
case 5:// 对学生成绩进行排序
paixu(L);
break;
case 6://输出所有学生的信息
display(L);
break;
case 7://保存学生信息到文件
saveStuDentFile(L);
break;
default:
printf("请输入正确的选择\n");
break;
}
}
}