《C程序设计》课程设计指导书0104.docx
- 文档编号:23115626
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:18
- 大小:45.34KB
《C程序设计》课程设计指导书0104.docx
《《C程序设计》课程设计指导书0104.docx》由会员分享,可在线阅读,更多相关《《C程序设计》课程设计指导书0104.docx(18页珍藏版)》请在冰豆网上搜索。
《C程序设计》课程设计指导书0104
长春理工大学光电信息学院
《C程序设计》
课程设计指导书
信息工程分院计算机实验室
一、课程设计的目的
采用结构化程序设计方法,综合运用C语言的基本知识,尤其是数组、函数、指针及流程控制等,并补充课程中虽未涉及但实用中必要的其他内容,实现一个功能较为齐全的程序实例。
二、设计题目
学生成绩管理系统。
程序的主要功能如下:
1、按学号记录一个班M名学生N门课程的期末考试成绩;
2、逐一显示M个学生的有关数据;
3、实现查找、删除;
4、能统计出补考学生及其相应科目。
三、设计的方法步骤
1、自愿结合,每2~3名同学为一组,选组长一名。
2、由组长主持,全组一起消化理解整个程序的基本功能。
在此基础上,明确每一名同学所承担的具体模块(函数)。
3、尽可能独立地实现系统的功能(组内同学可一起讨论),确有困难,可参照本指导书中所附的示范案例。
4、应认真研读本指导书中示范案例中的思考题,为答辩做准备。
四、课程设计报告的内容
1、课程设计目的;
2、课程设计题目及主要功能;
3、程序中用到的主要数据结构及程序的总体功能框图;
4、所实现的模块(函数)功能及源程序;
5、所实现的模块(函数)中最能代表你设计水平的②算法框图;(可选)
6、程设计的心得体会。
(可选)
五、答辩要求
1、以组为单位答辩,答辩时应提供能运行的完整程序及课程设计报告(每人1份)。
2、组长概述程序的总体功能及总的设计思路后,逐个同学上机演示你本人承担的模块功能并回答老师的提问。
3、提问问题中除指导书上列出的思考题,还包括老师随时针对你的源代码、框图等以及设计中涉及到的基本知识所提出的问题。
附1:
设计参考案例
a)设计的基本思路
我们采用C语言,VC6.0集成开发环境,字符用户界面,结构化程序设计方法。
依据N.Wirth的著名公式:
程序=数据结构+算法
其中数据结构要解决两个问题:
表示一个学生的属性及M个学生的集合;算法则应实现程序的功能。
二、数据结构
用一个结构体类型表示一个学生的属性:
typedefstructstudent{
longnum;/*学号*/
charname[20];/*姓名*/
intscote[N];/*N门功课考试成绩*/
structstudent*next;/*为构成链表而设*/
}Student;
我们采用单链表表示M个学生的集合,这主要是为了熟悉链表的操作。
所以在Student类型中事先已设置了next域。
。
我们也可以采用结构体数组表示M个学生的集合(当然应去掉Student中的next域)。
三、系统的功能框图
四、系统各功能模块(函数)的实现
1、主模块(main()函数)再任意选择两个模块书写
主模块的主要功能是反复显示菜单,根据用户的选项,调用相应的功能模块,直到用户选择退出。
参考程序如下:
#include"my.h"
charcourse[N][20];
voidmain()
{
Student*head;
Student*p;
charch;
longnum;/*numberofstudents*/
inti;
clrscr();
printf("\nEnter%dcoursenames:
\n",N);
for(i=0;i { fflush(stdin); gets(course[i]); } p=(Student*)malloc(sizeof(Student)); if(p==NULL) { printf("\nMemoryallocationerror."); exit (1); } else { p->number=0; p->next=NULL; strcpy(p->name,"headnode"); for(i=0;i p->score[i]=0; head=p; } do{ ch=menu(); switch(ch) { case'1': input(head); break; case'2': display(head); printf("\nEnteranykeytocontinue,please: "); getche(); break; case'3': delete(head); printf("\nEnteranykeytocontinue,please: "); getche(); break; case'4': printf("\nEnterthenumberofstudent: "); scanf("%ld",&num); p=search(head,num); if(p==NULL) printf("\n%ldnumberstudentisnotfound.",num); else dispnode(p->next); printf("\nEnteranykeytocontinue,please: "); getche(); break; case'5': reexamine(head); printf("\nEnteranykeytocontinue,please: "); getche(); break; case'6': printf("\nExittheprogramnow,bye_bye! "); exit(0); break; default: printf("\nYoushouldpress<1>---<6>"); if(ch=='\n'||ch=='\t'||ch=='') printf("\nchiswhitecharacter.\n"); else printf("\nch=%c\n",&ch); break; } }while (1); } _ 思考题: (1)main()函数中的循环怎样才能结束? (2)除了用do-while,还可用什么循环语句? (3)head所指的空节点的num域可用于表示什么信息? 2、显示菜单模块 显示一个字符界面的菜单,返回代表用户选项的一个数字字符。 参考程序如下: #include"my.h" charmenu() { charch; inti; clrscr(); printf("\n\n\t1---Input\n"); printf("\n\t2---Display\n"); printf("\n\t3---delete\n"); printf("\n\t4---Search\n"); printf("\n\t5---Reexamine\n"); printf("\n\n\t6---Exit\n"); printf("\n\n\t\tEnteryourchoice: "); fflush(stdin); ch=getche(); getche();/*waitfor returnch; } 思考题: (1)你能自己设计一个更美观好用的字符用户界面吗? (2)用单个字符代表用户的选项,如,I代表input,,则菜单程序应如何修改? (3)函数中的fflush()getche()起什么作用? 3、录入模块 录入学生的数据,以学号从小到大的顺序插入到链表中。 如果链表中已存在该学生,则给出提示信息,不重复录入。 一次可录入0…n名学生数据,当输入学号为负时,结束录入。 参考程序如下: #include"my.h" externcharcourse[N][20]; voidinput(Student*h) { longnum; Student*p,*q,*r; inti,n=0;/*nisnumberofinsertedinonecalling*/ charch; clrscr(); printf("\nEnterdataforastudent: \n"); printf("\nNumber: "); scanf("%ld",&num); while(num>0) { p=search(h,num); if(p! =NULL) { printf("\n%ldnumberstudenthasbeenexisted.",num); printf("\nReenternumberforastudent,please: "); fflush(stdin); scanf("%ld",&num); } else { p=(Student*)malloc(sizeof(Student)); if(p==NULL) { printf("\nMemoryallocationerror."); exit (1); } else { n++;/*incrementsnumberofstudents*/ p->number=num; printf("\nName: "); fflush(stdin); gets(p->name); printf("\nEnter%dexaminescores: ",N); for(i=0;i { printf("\n%s: \t",course[i]); scanf("%d",&p->score[i]); } } r=h; q=r->next; while(q! =NULL&&num>q->number) { r=q; q=q->next; } r->next=p; p->next=q; clrscr(); printf("\nEnterdataforastudent: \n"); printf("\nNumber: "); scanf("%ld",&num); } } h->number+=n; printf("\nThereare(is)%dstudent(s)were(was)inserted.",n); printf("\nThereare(is)total%ldstudent(s).",h->number); } 思考题: (1)在录入模块中,为什么要调用查找模块? (2)为什么在接收输入的学号时,另设一个变量num,而不直接使用p→num? (定p指向新近成功申请的节点) (3)插入新节点时,如何在原附加在表头,而与其它情况同样处理可以吗? (4)在此模块内,表头指针所指的空的头节点起到了什么作用? (5)在接收学生姓名时,用了库函数gets(name);比运用scanf("%s”,name)好处在哪儿? (6)不调用search(),代码应如何修改? (7)果用程序保证每门课的成绩在[0,100]范围内,怎样实现? 4、查找模块 在给定的链表中查找给定学号的学生。 找到则返回给定节点前驱节点的指针,找不到返回null. 这里所以要返回前驱节点的指针,而不是待查节点的指针,原因在于删除模块想调用查找模块,插入节点时要用到待删节点的前驱节点的指针。 这是本查找模块与一般查找不同的一个创意。 参考程序如下: #include"my.h" Student*search(Student*h,longnum) {Student*p,*q; q=h; p=h->next; if(p==NULL) returnNULL; else { while(p! =NULL&&p->number! =num) { q=p; p=p->next; } if(p! =NULL&&p->number==num) returnq; else returnNULL; } } _ 思考题: (1)此search()模块为何返回所查节点前驱的指针? (2)如果不考虑插入的需要,本模块应如何修改? 5输出补考名单 遍历整个链表,输出需补考的学生名单及补考课目。 这一功能很有实际意义。 它是在遍历链表的基础上进行筛选。 附带求出全班的不及格率。 参考程序如下: #include"my.h" voidreexamine(Student*h) {Student*p; intpass;/*logicvar.*/ inti; intnopass=0;/*numberofno-passstudent*/ clrscr(); if(h->number==0) printf("\nThereisnostudentinthelist."); else { p=h->next; while(p! =NULL) { pass=1; for(i=0;i { if(p->score[i]<60) { pass=0; nopass++; break; } } if(pass==0) { dispnode(p); printf("\nEnteranykeytocontinue,please: "); getche(); } p=p->next; } printf("\n\nThere%stotal%ldstudent(s)",h->number>1? "are": "is",h->number); printf("\nincluded%dstudent%cno-pass.",nopass,nopass>1? 's': ''); printf("\nNo-passpercentageis%.2f%%.\n",(float)(nopass)/h->number*100); } } 思考题: (1)能设计一个更好的输出格式; (2)int型变量pass的作用是什么? while循环中为什么有pass=1;这条语句 7、显示模块遍历链表,逐个显示学生的数据。 此模块功能与输出补考名单类似,只是不必筛选,因此更简单一些。 参考程序如下: #include"my.h" voiddisplay(Student*h) { Student*p; clrscr(); if(h->number==0) printf("\nThereisnostudentinthelist.\n"); else {p=h->next; while(p! =NULL) { dispnode(p); printf("\nEnteranytocontinue,please: "); getche(); p=p->next; }; } { intmany;/*indicatenumberofstudent>1? */ many=h->number>1; printf("There%s%ldstudent(s)",many? "are": "is",h->number); } } 思考题: (1)显示与输出补考名单模块有何相似之处? (2)自己设计一个更好的输出格式。 6、删除模块: 由用户指定待删除学生的学号,调用search()模块,若找到则删除,否则返回,一次只删除一个学生。 参考程序如下: #include"my.h" voiddelete(Student*h) {Student*p,*q; intnum; charanswer; clrscr(); printf("\nEnternumberofthestudentbeingdeleted: "); scanf("%ld",&num); q=search(h,num); if(q! =NULL) { p=q->next; dispnode(p); printf("\nDeletethestudent,areyousure? (Y/N): "); fflush(stdin); answer=getche(); answer=tolower(answer); if(answer=='y') { q->next=p->next; free(p); h->number--; } else { printf("\nYouchangeyouridea,bye_bye."); } } else { printf("\nThestudenttobedeletedisnotfound."); } } 思考题: (1)如果想一次可删除多个学生,此模块的程序代码应怎样修改? (2)free(p);起什么作用? (3)实际删除节点前,显示一下待删节点包含的信息,然后再次要求用户确认要删除此节点,你认为是否有必要? 程序如何实现的? 附2: 程序的调试: 一位著名的编程大师曾说过: “程序就是10%的灵感和90%的调试。 所有的编程高手都是调试的能手。 调试可分单模块调试和多模块联调。 关于调试的基本原则和方法以后在《软件工程》等相关课程中会深入探讨,我们在在此仅就以上案例说说具体作法。 为了调试每个模块,首先要对该模块单独编译,以便让编译器为我们尽可能地发现语法方面的错误,然后加以改正,直至编译成功。 然后,我们需要编写一个main()函数,调用该模块,以发现逻辑上的错误,并进一步分析对代码进行优化。 当可以正常执行后再仔细划分程序所能处理数据的各种情况,特别是边界上的数据,能否被正确处理;异常或错误的数据能否被程序所发现并剔除,例如,对menu()函数,就须反复调用,以验证在多次调用时是否每次都能按预期的方式工作。 案例中的fflush()就是在调试中发现问题后,通过查找资料而填加上的。 另外,各模块虽然相互独立,但逻辑上的有一定的先后次序。 建议调试次序先调menu(),search(),input(),然后调其它模块。 联调要建立项目文件(或称工程文件)。 具体操作方法是: 在TurboC2.0的集成开发环境下,用编辑器建一个一个项目文件,(.prj是必须的,文件名可选)内容如下: main.c menu.c input.c display.c dispnode.c search.c delete.c reexam.c 命名为student.prj然后在project下拉菜单,的PrjectName项下,注册上述项目文件名。 再接ctrl-F9菜单就自动对项目文件中所列的C源文件进行编译连接并加以执行了。 当然,在各模块正确通过编译后,联调还会产生一些错误,有些错误还比较隐蔽,需要耐心,细致地一一查找改正,这也是锻炼我们实际工作能力的好机会。 调试中要充分利用TurboC2.0集成开发环境提供的各种调试手段,如单步运行、设置断点、添加观察项等。 具体操作请参照教科书上的有关章节。 相信同学们经过艰苦努力,一定会有事前难以预想的收获。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C程序设计 程序设计 课程设计 指导书 0104