C语言程序设计
课程设计报告
设计题目:班级学生成绩管理系统
专 业:
班 级:
学 号:
姓 名:
指导教师:
时间:2011/06/12
目 录
一、 课程设计目的和要求……………………3
二、 课程设计任务内容………………………4
三、 程序流程图………………………………16
四、 软件使用说明……………………………17
五、 课程设计心得与体会……………………19
2
一. 课程设计的目的和要求
目的:本课程设计是计算机科学与技术专业重要的实践性环节之
一,是在学生学习完《程序设计语言(C)》课程后进行的一次全面的综合练习。本课程设计的目的和任务:
1. 巩固和加深学生对C语言课程的基本知识的理解和掌握
2. 掌握C语言编程和程序调试的基本技能
3. 利用C语言进行基本的软件设计
4. 掌握书写程序设计说明文档的能力
5. 提高运用C语言解决实际问题的能力
程序功能和要求:
1. 学生记录用结构体
2. 学生信息数据用文件保存
3. 采用多文件形式组织程序
4. 基本功能:
1) 增加学生记录
2) 文件存储
3) 读取文件
4) 删除记录
5) 修改记录
6) 查询记录
5.程序简洁易懂
3
二.课程设计任务和内容 代码:
#ifndef H_STUDENT_HH #define H_STUDENT_HH
#include<stdio.h> #include<stdlib.h> #include<conio.h> #include<string.h>
#define NUM_SUBJECT 5 #define INITIAL_SIZE 100 #define INCR_SIZE 50
struct student_info{ char number[15]; char name[20]; char gender[4]; float score[NUM_SUBJECT]; float sum; float average;
int index;
4
//科目数 //数组初始大小 //数组每次增加的大小 //学号 //姓名 //性别
//某学生的各科成绩 //总分 //平均分 //名次
};
typedef struct student_info StuInfo;
extern int numStus; //记录的学生数
extern StuInfo* records; //记录学生信息的数组 extern char savedTag; //信息是否保存 extern int arraySize; //数组大小
extern char* subject[];
void handle_menu(void);
int menu_select(void);
void addRecord(void);
void modifyRecord(void);
void display(void);
void queryInfo(void);
void removeRecord(void);
int saveRecords(void);
int loadRecords(void);
void quit(void);
void showTable(void);
int findRecord(char* target,int targetType,int from); void copyRecord(StuInfo* src,StuInfo* dest);
5
void sortInfo(void);
int findRecord(char* target,int targetType,int from); int getIndex(float);
#endif // H_STUDENT_HH
#include "student.h"
//******************输出表头********************** void showTable(void)
{
}
//****************显示所有学生信息函数******************
void display(void)
{
6 int j; printf("学号\t姓名\t性别"); for(j=0;j<NUM_SUBJECT;j++) printf(" %s ",subject[j]); printf(" 总分 平均分 名次\n");
int i,j; if(numStus==0) { } showTable(); for(i=0;i<numStus;i++) { printf("没有可供显示的记录!"); return; printf("%4s\t%3s\t%3s",records[i].number,records[i].name,records[i].gender);
printf(" %.1f %.1f %d\n",records[i].sum,records[i].aver for(j=0;j<NUM_SUBJECT;j++) printf("\ %.1f ",records[i].score[j]); age,records[i].index);
if(i%19==0 && i!=0) { printf("输入一行字符后继续...\n"); getch(); 7
printf("\n\n");
showTable();
}
}
}
//*******************在当前表的末尾增加*************************
void addRecord(void)
{
char str[10];
int j;
float mark,sum;
if(numStus==0)
printf("原来没有记录,现在建立新表\n"); else
printf("先面在当前的末尾增加新的信息\n"); while(1)
{
printf("您将要添加一组信息,确定吗?(y/n)"); 8 新的信息
)); gets(str); if(str[0]=='n' || str[0]=='N') break; if(numStus >= arraySize) { records=realloc(records,(arraySize+INCR_SIZE)*sizeof(StuInfo } if(records==NULL) { } arraySize=arraySize+INCR_SIZE; printf("memory falled!"); exit(-1); printf("请输入学号:"); gets(records[numStus].number); printf("请输入姓名:"); gets(records[numStus].name); printf("请输入性别(0为女,1为男):"); 9
} gets(str); if(str[0]=='0') strcpy(records[numStus].gender,"女"); else strcpy(records[numStus].gender,"男"); sum=0; for(j=0;j<NUM_SUBJECT;j++) { } records[numStus].sum=sum; records[numStus].average=sum/NUM_SUBJECT; records[numStus].index=getIndex(sum); numStus++; printf("请输入%s成绩:",subject[j]); gets(str); mark=(float)atof(str); records[numStus].score[j]=mark; sum+=mark; printf("现在一共有%d条信息\n",numStus); savedTag=1; 10
}
//************找出总分为sum在第0至numStus-1个记录中按升序排序的位置************
int getIndex(float sum)
{
}
11 int i; int count=0; for(i=0;i<numStus;i++) { } return count+1; if(records[i].sum<sum) { } else if(records[i].sum>sum) { } count++; records[i].index++;
#include "student.h"
//******************文件存储操作函数*********************
int saveRecords(void)
{
FILE *fp; char fname[30]; if(numStus==0) { } printf("没有记录可存!"); return -1; printf("请输入要存入的文件名(直接回车选择文件stu_info):"); gets(fname); if(strlen(fname)==0) strcpy(fname,"stu_info"); if((fp=fopen(fname,"wb"))==NULL) 12
}
{ } printf("不能存入文件!\n"); return -1; printf("\n存文件...\n"); fwrite(records,sizeof(StuInfo)*numStus,1,fp); fclose(fp); printf("%d条记录已经存入文件,请继续操作。\n",numStus); savedTag=0; return 0;
//************************文件读取操作函数****************************
int loadRecords(void)
{
13 FILE *fp; char fname[30]; char str[5];
if(numStus!=0 && savedTag==0) { printf("请选择您是要覆盖现有记录(y),还是要将"); printf("读取的记录添加到现有记录之后(n)?\n"); printf("直接回车则覆盖现有记录\n"); gets(str); if(str[0]=='n'||str[0]=='N') { } else { if(savedTag==1) { } numStus=0; 14 savedTag=1; printf("读取文件将会更改原来的记录,"); printf("是否保存原来记录?(y/n)"); gets(str); if(str[0]!='n'&&str[0]!='N') saveRecords();
} } printf("请输入要读取的文件名(直接回车选择文件stu_info):"); gets(fname); if(strlen(fname)==0) strcpy(fname,"stu_info"); if((fp=fopen(fname,"rb"))==NULL) { } printf("打不开文件!请重新选择\'n"); return -1; printf("\n取文件...\n"); while(!feof(fp)) { records=realloc(records,(arraySize+INCR_SIZE)*sizeof(StuInfo15 if(numStus>=arraySize) {
));
}
#include "student.h" 16 if(records==NULL) { } arraySize=arraySize+INCR_SIZE; printf("memory failed!"); exit(-1); } } if(fread(&records[numStus],sizeof(StuInfo),1,fp)!=1) break; //按照addRecord函数的方法,更新名次 records[numStus].index = getIndex(records[numStus].sum); numStus++; fclose(fp); printf("现在共有%d条记录。",numStus); return 0;
//******************文件存储操作函数*********************
int saveRecords(void)
{
FILE *fp; char fname[30]; if(numStus==0) { } printf("没有记录可存!"); return -1; printf("请输入要存入的文件名(直接回车选择文件stu_info):"); gets(fname); if(strlen(fname)==0) strcpy(fname,"stu_info"); if((fp=fopen(fname,"wb"))==NULL) { printf("不能存入文件!\n"); 17
}
} return -1; printf("\n存文件...\n"); fwrite(records,sizeof(StuInfo)*numStus,1,fp); fclose(fp); printf("%d条记录已经存入文件,请继续操作。\n",numStus); savedTag=0; return 0;
//************************文件读取操作函数****************************
int loadRecords(void)
{
FILE *fp; char fname[30]; char str[5]; if(numStus!=0 && savedTag==0) { 18
printf("请选择您是要覆盖现有记录(y),还是要将"); printf("读取的记录添加到现有记录之后(n)?\n"); printf("直接回车则覆盖现有记录\n"); gets(str); } if(str[0]=='n'||str[0]=='N') { } else { } if(savedTag==1) { } numStus=0; printf("读取文件将会更改原来的记录,"); printf("是否保存原来记录?(y/n)"); gets(str); if(str[0]!='n'&&str[0]!='N') saveRecords(); savedTag=1; 19
)); printf("请输入要读取的文件名(直接回车选择文件stu_info):"); gets(fname); if(strlen(fname)==0) strcpy(fname,"stu_info"); if((fp=fopen(fname,"rb"))==NULL) { } printf("打不开文件!请重新选择\'n"); return -1; printf("\n取文件...\n"); while(!feof(fp)) { records=realloc(records,(arraySize+INCR_SIZE)*sizeof(StuInfoif(numStus>=arraySize) { if(records==NULL) 20
} { } arraySize=arraySize+INCR_SIZE; printf("memory failed!"); exit(-1); } } if(fread(&records[numStus],sizeof(StuInfo),1,fp)!=1) break; //按照addRecord函数的方法,更新名次 records[numStus].index = getIndex(records[numStus].sum); numStus++; fclose(fp); printf("现在共有%d条记录。",numStus); return 0;
#include "student.h"
//*********************学生信息排序函数************************* 21
void sortInfo(void) {
char str[5]; int i,j; StuInfo tmps; if(numStus==0) { } printf("没有可供排序的记录!"); return; printf("请输入您希望进行排序的方式:\n"); printf("1.按学号进行升序排序\n"); printf("2.按学号进行降序排序\n"); printf("3.按姓名进行升序排序\n"); printf("4.按姓名进行降序排序\n"); printf("5.按名次进行升序排序\n"); printf("6.按名次进行降序排序\n"); printf("7.按错了,现在并不想进行排序\n"); gets(str); if(str[0]<'1'||str[0]>'6') return; 22
//进行排序 for(i=0;i<numStus-1;i++) { for(j=i+1;j<numStus;j++) { if((str[0]=='1' && strcmp(records[i].number,records[j].number)>0) ||
(str[0]=='2' && strcmp(records[i].number,records[j].number)<0) ||
(str[0]=='3' && strcmp(records[i].name,records[j].name)>0) ||
(str[0]=='4' && strcmp(records[i].name,records[j].name)<0) ||
} { } (str[0]=='5' && records[i].index>records[j].index) || (str[0]=='6' && records[i].index<records[j].index)) copyRecord(&records[i],&tmps); copyRecord(&records[j],&records[i]); copyRecord(&tmps,&records[j]); 23
} } printf("排序已经完成\n"); savedTag=1;
#include "student.h"
//初始化
int numStus=0; //记录学生数 StuInfo *records=NULL; //记录学生信息
char savedTag=0; //信息保存标志,1为未保存,0为已保存
int arraySize; //数组大小 char* subject[]={"高数","英语","线代","物理","电工","体育"};
//*****************主函数**************************
int main()
{
records=(StuInfo*)malloc(sizeof(StuInfo)*INITIAL_SIZE); if(records==NULL) { 24
}
} printf("memory fall!"); exit(-1); arraySize=INITIAL_SIZE; printf("\n"); printf("\t****************************\n"); printf("\t* 这是一个 *\n"); printf("\t* 学生成绩管理程序 *\n"); printf("\t* 可以对学生成绩进行管理 *\n"); printf("\t* 欢迎使用管理系统 *\n"); printf("\t****************************\n"); printf("\n"); handle_menu();
//******************菜单处理函数***********************
void handle_menu(void)
{
25
for(;;){
switch(menu_select()) {
case 1:
addRecord(); break;
case 2:
modifyRecord(); break;
case 3:
display(); break;
case 4:
queryInfo(); break;
case 5:
removeRecord(); break;
case 6:
saveRecords(); break;
case 7:
26
}
loadRecords(); break; case 8: sortInfo(); break; case 9: quit(); } }
//*********************菜单选择函数*************************
int menu_select()
{
char s[2]; int cn=0; printf("\n"); printf("\t1.增加学生信息\n"); printf("\t2.修改学生信息\n"); 27
}
printf("\t3.显示学生信息\n"); printf("\t4.查询学生信息\n"); printf("\t5.删除学生信息\n"); printf("\t6.保存学生信息至记录文件\n"); printf("\t7.从记录文件读取学生信息\n"); printf("\t8.排序学生信息\n"); printf("\t9.结束运行\n"); printf("\n左边数字对应功能选择,请选1-9:\t"); for(;;) { gets(s); } cn=atoi(s); if(cn<1||cn>9) printf("\n\t输入错误,重选1-9:"); else break; return cn;
//**********************结束运行*************************
28
void quit(void)
{
}
1.总体设计:
本设计有4个C文件(14个函数)和一个头文件组成,每个C文件都代表着某种特定功能,他们的关系如表12-1 所示。
程序包含头文件的存、取过程,其功能就是按输入顺序建立记录。如果原来没有记录文件,可以重新建立一个文件;
如果已经有记录,可以先把文件内容读入,然后把新记录追加到原来记录的尾部;也可以单独建立新文件,以后再使用 读取文件的方法拼装。
29 char str[5]; if(savedTag==1) { } free(records); exit(0); printf("是否保存原来的记录?(y/n)"); gets(str); if(str[0]!='n' && str[0]!='N') saveRecords();
表12—1 文件及函数组成
30
由上述功能分析可以看到改程序的全貌。因为它有并列选择,所 可以用选择菜单方便地实现。这个菜单具有8项,用switch语句可
以实现这些选择。所以用简洁的伪码对它们进行选择,因为并不复杂,所以这里不自在赘述。
2.函数具体设计
为一些函数设计两个返回值以区分其执行结果是否正确。每个学生信息资料用一个StnInfo结构来保存,用StuInfo数组的全局变量records来保存一批学生的信息资料。宏定义INTIAL_SIZE表示数组初始大小,当已分配的数组大小不够用时,敬爱那个增加数组大小, 31
INCR_SIZE为每次增加的大小。全局变量numStus 表示数组中记录的学生数,arraySize是为数组分配的空间大小。全局变量savedTag是信息是否保存的标志,当数组内容被保存只文件后,设为‘’以保存‘’状态,当数组内容被修改之后,设为“未保存”状态。
1) .文件存储操作函数
函数原型:int savedRecord(void)
功 能:将及录存入默认文件 stu_info 或者指定文件。 参 数:void。
返 回 值:成功0,失败-1。
工作方式:数组records被保存至指定文件。
要 求:报告是否有记录可保存、是否能正常建立或打开文件、
根据要求执行存入操作并报告存入记录的条数。
2) .文件读取操作函数
函数原型:int loadRecords(void)
功 能:将默认文件stu_info 或者指定文件里的记录存入内存。
参 数:void。
返 回 值:成功0,失败-1。
工作方式:records 为从指定文件中读取出记录。
要 求:报告是否有记录可存、是否能正常打开文件、是否覆盖已有记录以及读取记录的条数。
3) .显示所有学生信息函数
函数原型:void display(void)
功 能:显示内存里的记录信息。
33
参 数:void。
返 回 值:void。
工作方式:从头文件开始逐个显示记录内容。
要 求:报告是否有记录及记录条数和内容。
4) .增加信息函数
函数原型:void addRecord(void)
功 能:增加记录。
参 数:void。
返 回 值:void。
工作方式:从尾部开始逐个追加记录。
要 求:将新记录追加在记录尾部,并对记录进行计数。
5) .输出表头函数
函数原型:void showTable(void)
功 能:输出表头信息。
改表头里面含有学生学号,姓名,性别,及各学科名
称,总分,平均分,这样以后每一次要输出学生信
息是直接就可以用此函数,减少程序的代码,是程
序简单化。
参 数:void。
返 回 值:void。
工作方式:输出头一行表头信息。
要 求:输出一行表头信息。
34
6) .删除记录函数
函数原型:void removerecord(void)
功 能:删除内存数组中指定记录。
如果有的学生信息发生改变,你可以丢它进行删除,
删除之前,你必须找到你要修改学生的记录,你可以根据姓名,学号超找改学生的信息,找到之后,若要删除,就对它进行删除。
参 数:void。
返 回 值:void。
工作方式:根据给定的关键字,查找符合的记录并删除之。
要 求:将后面的记录前移,同时改变名次并给出相关信息。
7) .查找指定记录函数
函数原型:void findRecord(char*,int,int)
功 能:查找指定记录。
参 数:char *target:欲查找记录的某一项与target相同。 int targetType:表明通过哪一项来查找,0为学号, 1为姓名,2为名次。
int from:从第from个记录开始找。
返 回 值:int(找到的记录序号),若找不到则返回-1。 工作方式:根据给定的关键字,查找符合记录的序号。
36
要 求:找不到则返回-1。
8) .查找指定学生信息函数
函数原型:void queryInfo(void)
功 能:将一个文件的内容追加到另一个文件的尾部。 参 数:void。
返 回 值:void。
工作方式:可以按照学号、姓名或名次来查询。
要
9) .记录复制函数
函数原型:void copyRecord(stuInfo*, stuInfo*)
功 能:将src指向的一条记录复制给dest指向的记录。 参 数:StuInfo* src为源记录StuInfo* dest为目的记录。 返 回 值:void。
工作方式:将源记录逐条复制到目的记录。
要 求:正确复制字符串。
37
10) .修改指定学生信息函数
函数原型:void modifyRecord(void)
功 能:找到指定记录并修改。如果有的学生信息发生改变,
你可以丢它进行修改,修改之前,你必须找到你要
修改学生的记录,你可以根据姓名,学号超找改学
生的信息,找到之后,若要修改,就对它进行修改。
参 数:void。
返 回 值:void。
工作方式:可以按照学号、姓名活名次找到要修改的记录,确认
后方可修改。
要 求:同时需要调整名次。
11) .菜单处理函数函数
函数原型:void handle_menu(void)
功 能:处理选择的菜单命令。
参 数:void。
返 回 值:void。
工作方式:根据命令,调用相应函数。
要 求:给出结束信息。
12) .菜单选择函数
函数原型:void menu_select(void)
功 能:接受用户选择代码。
38
参 数:void。
返 回 值:int。
工作方式:返回命令代码整数值。
要 求:只允许选择规定键,若果输入不符合要求,则提醒用
户重新输入。
13) .结束程序运行函数
函数原型:void quit(ADDR*)
功 能:结束程序运行。
参 数:void。
返 回 值:void。
工作方式:根据要求决定在退出前是否将修改的记录存入文件。 要 求:结束运行之前,询问是否丢修改的记录进行存储。
14) 排序函数
函数原型:sortInfo(void)
功 能:对学生的总进行排序,可以按照升序,降序,对学生
成绩或学号进行准确的排名。
参 数:void。
返 回 值:void。
工作方式:对学生进行排序,可以根据需要,对学生的学号或者
成绩进行升序或者降序。你通过选择1—7中的选项
来满足你的需求。
要 求:升序或者降序。
39
15) .主函数
函数原型:void main(void)
功 能:控制程序。
参 数:void。
返 回 值:void。
要 求:管理菜单命令并完成初始化。
16) .头文件
文件名称:student.h
功 能:声明函数原型,包含文件及自定义宏和数据结构。 要 求:报告是否能正常打开文件执行存入操作及存入记录条
数。
#ifndef H_STUDENT_HH
#define H_STUDENT_HH
用来防止重复包含的。这种比较怪异方式,不如STUDENT_H那样清晰明了,目的是尽量避免可能出现的重复的宏定义。
在头文件是,对于系统库投文件,使用“<>”形势,表示从系统查找头文件;对于自己建立的头文件,如student.h,使用 #include“student”的形势,表示处理系统库目录外,还要从目录去查找头文件。
40
这14个函数只就爱你紧密相关的,如若要对函数进行删除,修改,就必须用到查找函数,只有通过从查找函数才能对它们修改删除。
三.函数主流程图
四、软件调试
显示出人机界面:
出现菜单,可以选择你要操作的选项: 42
如果你要添加学生信息,则可以按以下提示操作:
当你添加完学生信息,你可以对学生信息进行其它操作.
43
如你要对学生信息进行修改,可以按照如下方式:
你也可以对学生成绩进行排名:
你可以直观准确确的看到学生信息:
通过使用这个学生信息管理系统软件,可以轻松的管理学生信息,你可以对学生信息按照现实界面进行信息添加,删除,查询,排序等功能。
五.心得体会
我想说课程设计真是一件很累人很伤脑筋的事情,在两周的时间 44
里,我们每天几乎都要面对着电脑,上课时去机房写程序,回到宿舍还要继续奋斗;要是只是在电脑面前坐着也没有什么难过的,但是在电脑面前还要想着怎么去写代码,怎么去安排程序结构,怎么去实现想要的程序功能等等一系列的事情;特别是在调试程序的时候更是让人头痛,辛辛苦苦的写好了函数,等到调试运行就出现一堆错误,真的拿它没办法;有的时候还真是后悔当初自己选择了这样一个费精力的专业,不过还好有书本的基础知识、发达的网络通信、知识渊博的老师以及热心的同学的帮助,才使我能将那些问题一一解决!
虽然课程设计很苦很累,有时候还很令人抓狂,不过现在回想起来它给我的并不只是痛苦的回忆,它不仅让拉近了我和同学间的距离,而且对我们学习计算机语言还是很有意义的。
在还没有进行课程设计实训之前,我对C语言知识的掌握真的只能说是很肤浅,我只知道分开来使用那些语句和语法,对他们根本没有整体感念,所以在学习C语言时经常会感觉很盲目,甚至不知道自己学这些东西是为了什么。通过一周的课程设计,我们不仅巩固以前所学的基础知识,而且了解到更多的提升的内容,如学会了头文件include<conio.h>的用法,更学会了怎么样使用大多文件编程。这两个星期我对C语言有了更深入的了解,同时也建立起了一个对C语言的整体架构和编程思想;我还学到了很多课本上没有学到的东西,也了解了很多以前不了解的计算机语言方面的知识;他扩充了我的知识,也开拓了我的视野,让我们了解了我们学习计算机语言的目的和将来发展的方向。
45
通过这个课程设计,虽然只做了一个简单的学生成绩管理系统,但这个系统把它用来管理学生信息确实简单方便,从这个系统,我发觉到了C语言的巨大优势和作用,它所涉及到知识面十分广泛,对我们以后学习其他语言打下深厚的基础。
通过这次的课程设计,让我明确了学习C语言的目的和重要性,在以后的时间里,我会更加努力的把C语言学好,为以后学习更高级的计算机语言打下好的基础,并通过与老师同学的交流来不断的提升自己的编程和开发能力!
46
47