通达学院
程序设计
(2017/2018学年 第1学期)
题 目:学生选修课程系统设计与实现
专 业 计算机科学于技术(嵌入式) 学 生 姓 名 班 级 学 号 指 导 教 师 徐小龙
指 导 单 位 计算机学院·计算机科学与技术系 日 期 2017年10月27日
南京邮电大学通达学院
程序设计 指导教师成绩评定表
题 目 学生姓名 评分内容 班级学号 评分标准 认真对待课程设计,遵守实验室规定,上机平时成绩 不迟到早退,不做和设计无关的事。 设计的科学、合理性 专业 优秀 良好 中等 差 功能丰富、符合设题目要求 设计成果 界面友好、外观漂亮、大方 设计的原创性 设计报告 设计报告正确合理、反映系统设计流程 文档内容详实程度 文档格式规范、排版美观 简练、准确阐述设计内容,能准确有条理回答辩 答各种问题,系统演示顺利。 评分等级 指导教师签名 备注
日期 2017-10-27 评分等级有五种:优秀、良好、中等、及格、不及格
一、 课题内容和要求
学生选修课程系统设计与实现
假定有n门课程,每门课程有课程编号,课程名称,课程性质,总学时,授课学时,实验或上机学时,学分,开课学期等信息,学生可按要求(如总学分不得少于60)自由选课。试设计一选修课程系统,使之能提供以下功能:
(1) 系统以菜单方式工作
(2) 课程信息录入功能(课程信息用文件保存)--输入
(3) 课程信息浏览功能--输出
(4) 查询功能:按学分查询、按课程性质查询 (5) 学生可以选修课程
二、需求分析
本系统的功能模块如图所示
开 始
主 函 数 录 入 浏 览 课 查 询 课 进 入 选 统 计 选 课 将课 浏览文件中的按照学分查询按 照课 程性 质输入学号姓名从选课文件中程信息输
1. 使系统以菜单方式工作:输出个菜单,用于显示以从文件中加载的课程信息和若干个可选的功能选项。根据客户输入的选项来运行不同的功能,运行不同的函数。
2. 录入课程信息:使用户可以将课程信息输入文件
3. 浏览课程信息:使用户可以按照学分或者课程性质浏览文件中的课程信息
4. 进入选课操作:输入学号,姓名进行选课 5. 统计选课情况:从选课文件中统计信息
三、概要设计
(1)主函数的设计
在主函数中按照提示输入相对应数字进入相应的操作,同时,在输入序号数字错误时,会自动提示“输入错误,请重新输入”,然后,重新输入一个数字,继续进行相应的操作。 (注:输入的数字要在0~5之内) 算法设计如下:
S1: 从键盘上输入一个0~5的数字,进入相应的操作 S2: 如果选择序号1,则进入课程信息录入操作 S3: 如果选择序号2,则进入浏览课程信息操作
S4: 如果选择序号3,则进入查询课程信息操作 S5: 如果选择序号4,则进入学生选择课程操作 S6: 如果选择序号5,则进入统计选课情况操作 S7: 如果选择序号0,则退出学生选课管理系统
S8: 如果选择除0~5的其他操作,则提示“输入错误,请重新输入” 然后返回S1 具体流程图如下:
开 始
输入0~5相 应的操作对主 函 数
进行相应的操作
是 否 是
否
(2) 录入函数的设计
对于录入函数,就是在D盘建立一个“”文件,然后通过scanf从键盘上输入课程信息,再通过fprintf将输入的信息保存在文件中,关闭文件。
算法设计如下: S1: 在D盘建立“”文件 S2: 提示让学生输入选课门数 S3: 从键盘上输入课程信息并保存
结 束 S4: 当指针指向文件尾部,返回S3 具体流程图如下:
创建文件
输入课程门数
(3) 浏览函数的设计
对于浏览函数,通过fscanf读取文件中的课程信息,然后再通过
是 是否指保存课程信息 输入课程信息 开 始 结 束 printf将信息输出 算法设计如下: S1: 打开“”文件 S2: 读取文件中的信息 S3: 输出信息
S4: 当指针未指向文件尾部,返回S2 具体流程图如下:
开 始
输出课程信息
是否指 读取课程信息 打开文件
结 束
(4) 查询函数的设计
对于查询函数,输入1或2选择查询方式,如果不是,则重新输入。对于不同方式的查询,如果输入的方式与文件中有相符的,则输出查询结果
算法设计如下: S1: 选择查询方式
S2: 如果方式是学分查询,输入想查询的学分,打开文件,未指向文件尾部,如果文件中存在,则输出查询结果
S3: 如果方式是课程性质查询,输入想查询的课程性质,打开文件,未指向文件尾部,读取文件信息,如果文件中存在,则输出查询结果 S4: 如果方式数字不存在,则退出查询 具体流程图如下:
开 始
是 选择查询方式
按学 分 查 打开 是否存 是 是否指 是 输出课程信 按 课程打开是否存是 是否指是是 输出课程信息 数字不正只 显示 课程 编号、课程 名称 退出课程查询
结 束
(5) 选课函数的设计
对于选课函数,先从键盘上输入学号,姓名,课程编号,课程名称,打开“”文件,如果,课程存在,则进入下一步,建立“”文件,将选课信息保存在文件中,退出。 算法设计如下:
S1: 输入选课信息,包括学号,姓名,课程编号,课程名称 S2: 打开文件“”
S3: 如果课程存在,则进行下一步 S4: 建立“”文件 S5: 保存选课信息
具体流程图如下:
打开课程文件
输入选课信息 开 始 结 束 是否存
建立选课文件
读取选课信息保
结 束
(6) 统计函数的设计
对于统计函数,打开“”文件,读取文件中的选课信息,输出文件中的选课信息,计数,关闭文件 算法设计如下: S1: 打开“”文件
S2: 当未指向文件尾部,读取文件中的选课信息 S3: 输出选课信息同时计数 S4: 输出人数 S5: 结束 具体流程图如下:
开 始
是否指
打开选课文件
结 束
是否指否 输出选课信息计读取选课信息
四、详细设计
1.主函数:构造void main(),实现调用各个功能模块:
学生选课系统执行主流程如图所示,先执行主函数中显示菜单函数,通过循环和按键操作来执行相应的操作。按键的有效键值为0~5之间的任意数值,其他按
键为无效输入,会提示“输入错误,请重新输入”,同时,再次用scanf创造再次输入的机会。各个按键的执行功能为: “1”:录入选修课课程信,调用函数luru(); “2”:浏览录入的课程信息,调用函数liulan(); “3”:查询课程信息,调用函数chaxun(); “4”:进入选课操作,调用函数chaxun(); “5”:统计选课信息,调用函数tongji(); “0”:退出系统;
int main() { int n; int menu(); int f1(); int luru(); int liulan(); int chaxun(); int xuanke(); int tongji();
printf(\"\\n
***********************\");
printf(\"\\n\\n ********** **********\");
**********************
欢迎进入学生选课系统!
menu(); printf(\"\\n\");
printf(\" ******************* the end
*********************\\n\");
printf(\"\\n
**********************
***********************\");
printf(\"\\n\\n 请 先 选 择 1 进 行 课 程 信 息 录 入:\"); scanf(\"%d\ for(;n>5||n<0;) {
printf(\"\\n 输 入 错 误 !请 重 新 输 入 !\\n
\");
}
while(n>0&&n<6) {
switch(n) {
case 1:luru();break; case 2:liulan();break; case 3:chaxun();break; case 4:xuanke();break;
scanf(\"%d\
case 5:tongji();break; }
scanf(\"%d\ for(;n>5||n<0;) { printf(\"\\n\\n\");
printf(\"\\n \"); scanf(\"%d\
}
system(\"cls\");
} if(n==0) { printf(\" \\n\\n\\n\\n\\n\\n\\n\");
printf(\" ********** \"); printf(\"\\n\\n\\n\\n\\n\"); } exit(0); return 0;
}
输 入 错 误 ! 请 重 新 输 入 !\\n
谢谢使用! **********\\n 2.定义menu函数,f1函数方便调用函数
函数功能及实现:此函数为输出菜单,进入系统后提示可根据供选择的项目进行后续操作。
int menu() { int n;
printf(\"\\n\\n\\n\\n\");
printf(\" 1. printf(\" 2. printf(\" 3. printf(\" 4. printf(\" 5.
printf(\" 0. return 0; }
3.定义课程、选课结构体变量
struct course { int num; char name[20];
char kind[20];
录 入 课 程 信 息\\n\\n\");
浏 览 课 程 信 息\\n\\n\"); 查 询 课 程 信 息\\n\\n\"); 进 入 选 课 操 作\\n\\n\"); 统 计 选 课 情 况\\n\\n\"); 退 出 选 课 系 统\\n\\n\");
int ttime,mark,term;
}c;
struct student {
int snum;
int cnum; char cnam[20]; char snam[20];
}s[500];
4. 定义录入函数,课程信息
函数功能及实现:此函数录入课程信息,在查询、浏览、进入选课,查看选课信息等函数之前。定义指向文件的指针变量*fp,课程信息结构体c通过fopen函数建立文件””,后输入录入课程的门数,打印表头,通过for循环,用scanf函数从屏幕读取课程信息,并通过fprintf函数将课程信息录入到文件“”中,最后输出主菜单,返回主程序。
int luru() {
FILE *fp; struct course c; int count;
}
int i;
if((fp=fopen(\"\ { }
printf(\"\\n 请 输 入 选 择 的 课 程 门 数:\"); scanf(\"%d\ printf(\"\\n\\n\\n\"); f1();
for(i=0;i printf(\"\\n 录 入 成 功!\\n\\n\"); menu(); return 0; scanf(\"%d%s%s%d%d%d\ fprintf(fp,\"%d\%s\%s\%d\%d\%d\\ printf(\"cannot open file\\n\"); exit(0); 5.定义浏览函数,浏览录入的课程信息 函数功能及实现:此函数先定义指向文件的指针*fp,课程结构体变量c,通过if语句判断文件是否存在,在调用函数f1(),输出表头信息,通过for循环并使用fscanf函数将文件中的课程信息读出并通过printf打印到屏幕上,再通过fclose函数关闭文件。 int liulan() 学 分 查 询\\n\"); printf(\"\\n 2.按 课 程 性 质 查 询\"); printf(\" 请 选 择 查 询 方 式 \\n\\n 输 入 选 项 数 字:\"); scanf(\"%d\ for(;b<1||b>2;) { printf(\"\\n 输 入 错 误 !请 重 新 输 入 !\\n \"); } if(b==1) { printf(\"\\n 输 入 你 要 查 询 的 学 分: \"); scanf(\"%d\ if((fp=fopen(\"\ { printf(\"\\ncannot open course!\\n\"); scanf(\"%d\ } } exit(0); f1(); while(!feof(fp)&&i printf(\"%7d%11s%10s%9d%9d%8d\\n\ i++; else if(b==2) { printf(\"\\n\\n 输 入 你 要 查 询 的 课 程 性 质:\"); scanf(\"%s\ if((fp=fopen(\"\ if((fp=fopen(\"\ fclose(fp); }while(flag); printf(\"\\n ********* 恭喜选课成功!*********\\n\"); menu(); } return 0; 8.定义统计函数,统计学生选课信息 函数功能及实现:此函数为查看选修课被选择的情况。定义了变量total为了统计选课人数,通过if语句判断是否存在文件“”,通过for循环打印出所有已选课学生的学号、选课课程编号和所选课程的名称,通过计数变量total输出已选课的人数信息。然后打印菜单,返回主函数。 int tongji()num,s[i].snam,&s[i]um,s[i]am); } } t=i; for(i=0;i printf(\"\\n 选课学生总人数为:%d人\ fclose(fp); menu(); return 0; 源程序代码: #include<> #include<> #include<> struct course { int num; char name[20]; char kind[20]; int ttime,mark,term; }c; struct student { int snum; int cnum; char cnam[20]; char snam[20]; }s[500]; int count; 录 入 课 程 信 息\\n\\n\"); printf(\" 2. printf(\" 3. printf(\" 4. 浏 览 课 程 信 息\\n\\n\");查 询 课 程 信 息\\n\\n\");进 入 选 课 操 作\\n\\n\"); printf(\" 5. 统 计 选 课 情 况\\n\\n\"); printf(\" 0. 退 出 选 课 系 统\\n\\n\"); return 0; } int f1() { } int luru() 学 分 查 询\\n\"); printf(\"\\n 2.按 课 程 性 质 查 询\"); printf(\" 请 选 择 查 询 方 式 \\n\\n 输 入 选 项 数 字:\"); scanf(\"%d\ if((fp=fopen(\"\ fclose(fp);num,s[i].snam,&s[i]um,s[i]am);num,s[i].snam,s[i]um,s[i]am); printf(\"\\n 选课学生总人数为:%d人\ printf(\"\\n 课程编号 课程名称 课程性质 总学时 学分 开课学期:\\n\"); return 0; fclose(fp); 照学 分查询: b.按照课程性质查询: (5)、进入选课操作: (可以多次选择) (6)、统计选课信息 (7)退出选课系统 (按0退出操作系统) 五、调试过程中的问题 (1) 调试步骤 先进入菜单函数,选择数字进行相应的操作,然后,先进入录入函数阶段,通过键盘输入相应的课程信息,同时,创建一个“”文件,将输入的课程信息保存在文件中。然后,进入浏览函数阶段,先读取课程文件中的课程信息,然后将信息显示到屏幕上。接着,进入查询函数阶段,通过学分或者课程性质,查询相 应的课程信息。随后,进入选课函数阶段,通过输入学号和姓名,进行选课操作,并创建一个“”文件,将选课信息保存其中。最后,进入统计函数阶段,读取选课文件中的信息,统计选课人数,并将选课信息显示在屏幕上。选择序号0退出选课系统。 (2)发现的问题 1. 在用scanf函数给普通变量输入数据时,在变量名前漏写地址运算符&。 如:scanf(“%d”,count);同时,不能少掉上引号和分号。 2. 输入数据时的数据形式与要求不符。用scanf函数输入数据时,必须 注意要与scanf语句中的对应形式匹配。 如:scanf(“%d,%d”,&x,&y);输入数据时,不能输2 3,而是应 该用2,3 3.可以用scanf输入一个字符串,如果要用它输入多个字符串,输入时,中间要用空格分开。 如:scanf(“%s%s%s”,str1,str2,str3);输入数据 how are you 4. 混淆“=”和“==” 在C语言中,“=”是赋值运算符,“==”是关系运算符。 如:if(i==1)不能写成if(i=1) 5. 在不该出现分号的地方加了分号 如:if(x>y);在if后面是不用加分号的 6. 不能超过数组的最大值使用,在引用数组元素时,下标从0开始,即 下标的下限是0,而下标的上限值是数组定义时元素个数减1。 7. 在switch语句的各分支中未使用break语句。 如:switch(n) { case 1:luru();break;统计时出现中文 (2) 解决问题 1.对于语法中的错误,可以通过系统自动查出。 2.像逻辑错误,即算法中的问题,要通过不断检验算法,观察它逻辑中的错误。同时对于运行中出现中文的问题,是因为对于数组的未初始化或者定义空间过小等出现的。 3.对于可以创建,但是无法链接的问题,可能是未关闭运行窗口,或出现拼写中的错误,还有,像字符串的前面是不用加地址符的。 4.还有,出现最后一行多输出一次的问题,那就是在循环里面,应该先检 查它所在的文件中是否多有一行,如果文件中多一行,那就是保存时出现问题,如果是文件中是正确的,那问题就可能出现在输出函数时,循环中多进行一次 七、课程设计总结 为了更好的复习C语言的基础知识,进一步加深对C语言编程的理解,老师给每个人布置了完成一个操作系统的任务。这对于我们来说,无疑是一个巨大的挑战。因为链表是刚刚学习的,还不太熟练,我选择了用结构体和数组来构建我的系统。我知道,对于链表,我们应该熟练掌握,但是,在以后,我会多看书,加深对链表的理解。而且,通过这次作业,我懂得了如何做一个完整的系统,我明白一个好的系统,是要分成很多模块,而不是单纯的堆叠在一个主函数里,对于同一种性质的,最好将他们放在另外一个函数里,方便多次调用,并且,避免 了不必要的繁琐。自己编一个程序,才了解到其中的不易,每次出错,都会揪心,每次解决小小的问题,就会情不自禁的欢喜,看到错误栏显示的错误不断变少,就感觉成功更进一步。虽然我的程序没有用到很复杂的东西,但是,我觉得,我编的程序还算层次分明,每个模块分工详细,各尽所能。 而且,我还了解到独立思考的重要性。平时,上机课,我们都是习惯性的将书上的程序照原样打一遍,这样,并不能锻炼到我们的能力,而是,成为了一个单纯的打字员。所以,我们应该改变这种方式,我们应该学着自己思考问题,想想算法,如何实现各个模块的链接,如何通过循环读取一系列数据,然后将它保存,另外存在文件中,然后再读取。 另外,我还掌握了有关文件的一些知识,例如,定义指向文件的指针,文件的保存,文件的读取,文件的格式,读写文件,只读文件,只写文件,指向末尾的文件等等。还掌握了文件中的一些函数与普通的区别。fscanf和scanf的区别,fprintf与printf的区别,还有标准库函数stdio与stdlib的区别,库函数中的清屏,退出程序的函数,随机函数等,字符串调用函数,对字符串比较,字符串的复制,以前,不会那么详细的去了解这些知识,但是,自从编了这个程序之后,就要不断翻书,加深对这些边边角角的知识的理解,而不仅限于开始的了解。经过看书之后,对那些函数有了更深的理解。 还有,我明白在任何事情中都要细心。无论是在程序设计方面还是其他方面。每一个细微的错误,就可能导致程序无法运行,即使是一个小小的标点符号也不可忽视。同时,我掌握了检查错误的一个小窍门。就是将错误细化,可能一个程序中包含很多个函数,我每次出现问题时,都将每个函数单独提出来,那样就可以将错误细化到很小的部分,毕竟程序那么多,那么复杂,从头到尾都看过来,那是很困难的。但是将他们分开,就可以避免这个问题。还有,比如说像输出结果多一行的问题,本来是毫无头绪,而后来,将问题细化,发现了问题的共性,发现都是指向文件尾部的指针那里,对于指向尾部这个条件,每次出现这个条件时,系统浏览出来的数据,或者查询的数据,最后一行都是会重复输出一遍,这 时,我在保存文件的后面加了一个printf函数,这样,就可以知道,到底在文件保存之后,有没有出问题。如果在文件保存之后出现问题,那就是下面读取时有错误,但是,如果是没有问题,那就是保存文件的问题。最后,发现都没有问题,而且打开文件后,发现,保存的文件都没有问题。才发现原来是输出循环出现问题,并且问题都是共性的。都是使用while(!feof(fp))这个条件时,没有注意到这个指向文件末尾的函数,在指向文件末尾后,会再输出一次,然后,我找到了解决的方法,定义一个count 表示课程门数,用i 因篇幅问题不能全部显示,请点此查看更多更全内容