C语言程序课程设计报告.doc

上传人:来看看 文档编号:5014227 上传时间:2020-01-28 格式:DOC 页数:31 大小:155KB
返回 下载 相关 举报
C语言程序课程设计报告.doc_第1页
第1页 / 共31页
C语言程序课程设计报告.doc_第2页
第2页 / 共31页
C语言程序课程设计报告.doc_第3页
第3页 / 共31页
C语言程序课程设计报告.doc_第4页
第4页 / 共31页
C语言程序课程设计报告.doc_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《C语言程序课程设计报告.doc》由会员分享,可在线阅读,更多相关《C语言程序课程设计报告.doc(31页珍藏版)》请在三一文库上搜索。

1、C语言程序设计课程设计报告完成任务:1 用二分法求方程根2 矩阵求逆3 链表制作4 二十四点游戏5 学籍管理程序专业:计算机科学与技术班级:计二班学号:0705010225姓名: 本人于2008年9月1号在计算机中心6号机房25号机器上完成了本次课程设计。课程设计过程中使用的操作系统是Windows 2000,主要开发平台VC+ 6.0。任务二 用二分法求方程根目的与意义用二分法求方程f(x)=x3-x-1=0在区间1.0,1.5内的一个实根,要求准确到小数点后第2位。任务分析方程在区间1.0,1.5上单调并且存在一个根。取区间中点,确定方程的根在左右哪个区间(或者恰好是区间中点)内,这样一次

2、就可以把区间缩小一半,重复做此步骤直到满足精确度为止。方程的近似根为区间中点。取区间中点:只需用区间的两个端点相加,在除以2即可。确定根所在位置:区间a,b中,取中点c=(a+b)/2,与a,b构成两个区间:a,c与c,b。而方程的根的位置有三种可能1.在区间a,c中;2.在区间c,b中;3.根就是中点c。若中点就是方程的根,则可以直接输出。若不是这是剩下两种情况。若f(c)*f(a)0,则根在区间a,c中,若f(b)*f(a)0,则根在区间b,c中,两者只有一种情况成立。验证是否满足精确度:精确到小数点后两位,就是说0.01.。由于是用二分法,所以到了0.01后,还要继续二分,直到0.01后

3、才能满足精确度。也就是说,区间左右值相减要小于0.001时,输出区间中点即可。数据结构设计此程序将涉及三个变量:区间的两个端点,区间中点。由于要精确到小数点后两位,所以必须设置为float类型。还有一个函数,由于只需要验证返回值的正负,所以只需用int类型就可以了。后来在函数运行中出现错误,更改为float类型(具体错误将在“代码调试与运行”部分说明)。关键算法设计本程序比较小,原本只用一个main函数就可以完成,可是由于方程的函数每次输入比较麻烦,所以设置了一个简单的函数:Int hanshu(float x)return x*x*x-x-1;用它来返回方程函数的带入值。程序的关键在于不断二

4、分,确定根所在位置的循环算法。此循环代码如下:dof=(a+b)/2;if(hanshu(f)=0)printf(方程的根为%.2fn,f);break;if(hanshu(a)*hanshu(f)0.001);首先给f赋值为区间中点。若它满足hanshu(f)=0,说明f为方程的根,直接输出f,并用break语句,结束循环。如果不满足,则验证根在哪个区间,并执行相应赋值,形成新的区间,继续执行循环。循环在执行到满足精确度时结束,即b-a=0.001,结束循环。输出方程的根最好区分开此根是近似根还是准确根。所以把输出分为两部分。一部分在循环内,验证区间中点为准确根的时候输出。若要输出近似根则要

5、循环结束后,所以输出语句在循环结构外面。为了验证循环结束后得到的根f是不是准确根,顾输出语句在if语句内。代码如下:if(b-a0.01)printf(方程的近似根为%.2fn,f);代码调试与运行原程序运行时结果出人预料:方程的根为1.25注意到1.25恰好是原来区间的中点,而根据输出来看,1.25是方程的精确根。可是经过计算我得到方程的根应该在1.3到1.4之间。会输出这个结果,也就是说程序执行了if(hanshu(f)=0)printf(方程的根为%.2fn,f);break;为什么会这样?我想起返回函数带入值的函数hanshu()的返回值是int。如果返回值没有整数部分,就会返回0。所

6、以把它更改为float类型,最终得到结果:1.33。屏幕显示为:方程的近似根为1.33小结与体会每项数据在数据设定时需要细致详细的考虑数据的用途,以及可能出现的错误。注意每种数据的范围以防止程序运行中出错。一个简单的程序,也不能保证一次编写毫无错误。尤其在DEBUGE系统不能检验出错误,但是结果又不是期望值时,必须重新检查程序,任何细小的地方都可能是出错的原因。本人于2008年9月2号到2008年9月5号在计算机中心6号机房14号机器上尝试了本次课程设计。课程设计过程中使用的操作系统是Windows 2000,主要开发平台VC+ 6.0。由于各种原因至今没有完成,个大函数已经完成,但是在运行中

7、出现错误的原因没有找到。任务一 矩阵求逆目的与意义给定一个8X8的矩阵A,求出它的逆矩阵A-1。矩阵的元素由键盘中输入,首先判断矩阵是否可逆,若可逆则求出其逆矩阵并在屏幕上用适当格式显示出来。程序可以把矩阵求逆这一复杂的运算由计算机代替计算,既可以保证结果的准确,又可以高速度的完成复杂的计算。任务分析根据线性数学的学习知道,矩阵求逆有两种方法:单位矩阵化归法、伴随矩阵法。根据指导上的分析,第一种需要三个函数。那就是:行交换、将第n行乘以e、第i行乘以k加到第j行。这三个函数都不难做,但是如何利用这三个函数,求出逆矩阵我却无从下手。我只好用另外一种方法做。用伴随矩阵求逆矩阵需要两个函数:求矩阵行

8、列式、计算代数余子式。而这两个函数在使用中又相互使用,也就是相互调用。利用相互调用,就可以吧求你矩阵所需的的代数余子式和矩阵行列式求出来。求出矩阵行列式就可以验证矩阵是否存在逆矩阵。由代数余子式得到矩阵的伴随矩阵,两者相除就可以得到矩阵的逆矩阵了。数据结构设计 程序里输入输出都是矩阵,自然用二维数组。矩阵不见得都是整数,所以用float来定义最好。在带入两个函数时需要函数的阶数,这个一定是正整数,用int定义就可以。两个函数举证的行列式肯定是用float定义。求代数余子式的函数还要传入行数和列数,用int定义就好。关键算法程序关键算法就是两个。一是计算方阵的行列式,另一个是计算方阵对于某个元素

9、的代数余子式。由于两个函数相互调用,所以在函数中会有另一个函数的函数声明。我的求方阵行列式函数声名为float hangleishi(int n,float x88),其中n表示方阵的阶数。求代数余子式的函数声明为float yuzishi(int n,float x88,int i,int j),其中n表示阶数,i,j表示求方阵对于第i行,第j列的代数余子式。求方阵行列式的函数代码如下:float hangleishi(int n,float x88)float h;int i=0;float yuzishi(int n,float x88,int i,int j);/*函数声明*/if (

10、n=2)h=x00*x11-x01*x10;elsefor(i=0;i2时,函数执行else 的语句。语句中使用了求代数余子式的函数,是求行列式的一般求法,也是普遍求法。没有技巧,但是编程简单,算法也容易实现。n=2时,就可以直接算出来,返回h即方阵的行列式。降阶在函数yuzishi()中实现。求代数余子式的函数如下:float yuzishi(int n,float x88,int i,int j)int a=1,c=0,d=0;float h=0;float y88;for(c=0;ci;c+)for(d=0;dj;d+)ycd=xcd;for(;cn-1;c+)for(;dn-1;d+)

11、ycd=xc+1d+1;h=hangleishi(n-1),y);for(;ashuzi=n;p1-next=NULL;if(head=NULL)head=p1;elsep2-next=p1;p2=p1;scanf(%d,&n);return head;首先确定链表是否已经创建,如果已经创建,就结束函数返回。如果没有就进入创建函数。由用户输入n的数值,如果不是结束识别符(999999),函数就会用malloc申请一个新空间,并强制赋值为struct zhengshu*类型,并赋值给指针P1。如果head为空,就把p1的值赋给head,否则赋给p2。这样继续下一次循环,p1又被重新赋值。知道用户

12、输入999999,结束循环 。返回值head赋值给原来的head,表头被改变,链表创建完成。插入函数分为几个部分,一个是查询部分,另一个是插入部分。查询部分与其他的函数基本相同。查询部分在此介绍,以后部分不再做具体介绍。查询部分代码如下:printf(请输入插入点前面的整数数值n);scanf(%d,&a);p1=head;doif(p1-shuzi=a)b+;printf(检索成功!n);break; while(p1-next!=NULL)先由用户输入插入节点前面的节点数值,这样搜索开始。搜索中,定义一个指针。当指针指向的节点不为空时,则验证是否节点值为要搜索的数值。如果不是,则继续赋值为

13、下一个节点。这个搜索函数有一定弊病,那就是不能找到第一个节点值,所以在这个函数之前,我已经设置了函数问用户是否把节点插入在第一个位置。这样对这个漏洞做了有效的补救。插入函数第二部分,插入操作部分:printf(请输入新节点的数值n);scanf(%d,&a);p2=(struct zhengshu*)malloc(sizeof(struct zhengshu);p3=p1;p1=p1-next;p2-shuzi=a;p3-next=p2;p2-next=p1;printf(插入结点成功!n);这是插入函数的一部分,是在把新节点插入到链表中间位置时的函数。插入到最前端和最后端函数稍有不同,已插入

14、中间为例介绍。首先要求用户输入新节点的值,然后用malloc函数申请一个新空间,把类型转换为struct zhengshu *,并把它赋值给指针p2。这样在经过一系列赋值语句,就可以使前面节点的的指针指向新节点,而新节点下的新指针指向下个节点,完成新节点的插入。节点的修改比插入节点要简单一些,只需找到节点并对节点的数值重新赋值就可以了。而节点的删除函数跟节点修改很相似,只不过是把赋值语句更改为空间释放,并多加一个指针赋值而已。下面只介绍节点的删除函数:if(b=0)printf(链表中无此节点 n);elseif(p1-next!=NULL)p2=p1;p1=p1-next;p2-next=p

15、1-next;free(p1);printf(删除节点成功!n);elsep2-next=NULL;free(p1);大家可以看到,我在前面的搜索语句中加入了一个b+语句。这个语句的作用是来判断查询语句的循环结束,究竟使由于p1-next=0还是找到了要查找的数值,由于break跳出的循环。如果b被重新赋值说明成功搜索到了节点。在这个函数里,首先看b是不是还为0,如果是说明没有找到节点,输出未找到。如果不是,则说明找到了节点,而且这是p1的next正指向这个节点。把它赋值给P2,并使p1指向下一个节点,也就是要查找的节点。然后执行p2-next=p1-next,这样就把p1所指的节点,从链表中

16、摘下来了。然后用free语句把空间释放,就完成了节点的删除。链表的撤销函数跟删除函数很是相像,只是依次释放各个节点罢了。我编的函数代码如下:struct zhengshu *chexiao(struct zhengshu *head)struct zhengshu *p;p=head;if(p=NULL)printf(链表未创建n);elsewhile(head!=NULL)p=head;head=head-next;free(p);printf(链表撤消成功!n);return head;如果链表没有创建则直接返回。如果找到了,就用一个指针指向它,并把他的空间释放,而这时head已经指向了下

17、一个节点,指针又会被重新赋值。循环一直到head指向NULL时结束,这时链表的空间都被释放,链表撤销结束。链表的输出不过是一个循环的输出语句,在此不做介绍。结束函数也只是一些场面话,没有什么具体意义。下面使纵览全局的主函数:void main()printf(欢迎使用本链表制作程序!n海波制作群预祝您身体健康,万事如意!n如果您使用中发现BUG,请与我们联系n);printf(电话:15898523371 QQ:279528056 联系人:李海波nnnn);void caidan();struct zhengshu *chuangjian(struct zhengshu *head);stru

18、ct zhengshu *charu(struct zhengshu *head);struct zhengshu *xiugai(struct zhengshu *head);struct zhengshu *shanchu(struct zhengshu *head);struct zhengshu *chexiao(struct zhengshu *head);void print(struct zhengshu *head);void jieshu ();struct zhengshu *head;int a=0;head=NULL;loop:caidan();scanf(%d,&a)

19、;switch(a)case 1:head=chuangjian(head);goto loop;case 2: head=charu(head);goto loop;case 4: head=xiugai(head);goto loop;case 3:head=shanchu(head);goto loop;case 5:head=chexiao(head);goto loop;case 6: print(head);goto loop;case 7: jieshu();主函数的布局我尽量做得规范。最上面是所有函数的声明,然后是各种类型变量的定义,之后就是loop后面的语句。Loop后首先执

20、行菜单函数,输出菜单。然后是switch语句执行相应函数,执行结束后直接由goto语句返回loop。这样菜单再次输出,功能在此重新选择。调试与运行调试过程中出现了很多错误,还有一些设计上不合理的地方。这些错误大部分已经被更正,或是做了修改和补救。例如,插入节点查询函数采用查找节点数值的方式,无法找到最前面数值的问题。我加了一个询问语句,和表头节点的插入补救。结束函数,由于都是printf语句,真正的exe文件执行的时候会执行玩这些立刻结束,我加了一个输入语句,使用户可以看清楚结束的话,在自己想结束的时候输入一个字符结束程序。我已经对程序里各项功能做了比较详细的测试,程序的功能可以正常运行,不会

21、出现意想不到的结果。但是在测试中发现了一个问题,至今没有解决。那就是,按照节点数值查找,无法解决有相同节点的问题。如果有两个节点,程序只会对第一个节点进行操作,会完全忽略掉。这样使整个程序变得和不完整。因为几乎所有的重要函数都用到了查询函数。如果更改查询函数,就会“牵一发而动全身”,整个程序各部分都要重新更改,由于时间关系我没有做改动,这时本程序需要改进的地方。小结与体会这个程序是我独立完成的第一个比较大的程序,当然对于那些真正的大程序来说,这个不尔尔。可是对我来说不一样,我真的用心在做。做的过程中遇到不少麻烦,也曾经止步不前,可是我最终还是把它成功编写出来了,我觉得很有成就感。虽然程序中还有

22、很多弊病在里面,说不上一个完善的程序,但它终究是我努力的结果。在编写程序时,一边写就会一边发现很多的问题。写得时间越长,发现的问题也越来越多。一个个把问题解决掉真的很开心。可是我觉得,真正编写程序不应该是这样的。应该在写程序之前,就把所有的问题想清楚。这样可以给自己剩下大量的时间,而且程序看起来也会浑然一体,而不是“各自为战”。这个程序还让我感觉的,各个函数相互独立的方式编辑函数很有优越性。一个函数只负责而且可以独立负责一个功能,就可以避免,函数之间相互调用,把简单的问题复杂化。这样很容易找到问题发生的地方,并修改不必考虑对其他函数的影响。本人于2008年9月9号到2008年9月12日在计算机

23、中心6号机房12号机器上尝试完成了本次课程设计。但是由于时间关系,没有能全部完成程序的编写任务。课程设计过程中使用的操作系统是Windows 2000,主要开发平台VC+ 6.0。任务五 学籍管理目的与意义在某大学的一个专业,里面有四个班,每个班最多可以有40个学生。每个学生有学号、性别、籍贯等数据。在某个学期,他们开了高等数学一、英语一、线性数学、离散数学一、高等物理、思想品德教育、体育等8们课程,每门学分依次为3、3、2、2、2、1、2.。编制一个程序,使用户方便管理他们的学籍信息。需要输出没管的功能菜单。对于每个学生,可以进行基本情况的录入、查询、修改、删除。还有学生成绩的录入,查询,个

24、人加权成绩计算,修改等。还要完成班里加权成绩的平均分计算和排名。要求所有的数据用文件形式存取。还要设置管理员的权限和密码管理。任务分析根据我以前编写链表程序的经验,我想这次还是采取各个函数独立完成一项功能,彼此不相互调用的形式完成这次编程任务。首先要建立一个菜单,菜单上显示所有的功能,以便于用户选择相应的功能。但是美观很难做到,因为我知道机房的gotoxy的函数是不能用的。我就决定先把真材实料的东西做完,至于美观,在做完各个函数之后再去考虑。四个班的文件分开存放的,也就是说分4个文件存放。这样在执行其他功能时,必须要用户输入要进行操作的班级,不过这样省去了在一个文件中分出四个班的麻烦。录入函数

25、是一个比较重要的函数,因为所有的操作都是再文件的进行的,所以难度增加了不少。但是这是必须的,总不能输入一次看一次。录入函数中,肯定是用“w”形式打开文件,因为这里只有文件的写入。我想这函数肯定要设计一个结构体的类型的。所以用fwrite函数成块写入文件是最恰当的。查询个人信息函数中,文件用“r”,也就是只读形式打开。当然是用fread函数成块读出文件信息,并对它进行操作。查询至少要两种查询路线,也就是按姓名和按学号。这两种都是常用的搜索,所以都要包括在内。查询班级信息函数,必须输出班级的加权平均分。我决定在录入函数中直接由程序算出学生的加权成绩存储起来。另外是班级排名,使用冒泡法排序代码简单,

26、又容易实现。由于时间关系,删除,修改和管理权限、密码设置都没有完成。数据结构设计这里的数据用结构体是毫无疑问的。我的数据类型定义为:typedef structchar xingming9;char xuehao11;char xingbie3;char jiguan9;float chengji9;xue;学号、姓名、性别、籍贯都用char,也就是字符串类型定义。单科成绩共有8门,用float定义一个9个元素的数组,最后的用来存放学生的加权成绩。我在程序里还定义了一个结构体:typedef structchar xingming9;char xuehao11;float jiaquan;ss

27、;这是在班级加权成绩是用到的数据类型。因为在班级排名时,我们只关心学生的姓名、学号还有他的成绩,所以我们只使用这三个元素,没有必要在用原类型了。关键算法菜单函数只是一些输入函数,用来提示用户选择相应的功能。由于没有在美观上下工夫,所以我的菜单函数十分简单,只是一些输出函数而已。信息的录入函数如下:void luru()printf(您要录入哪个班的成绩?请输入数字n);int a=0;FILE *p;xue b;scanf(%d,&a);switch(a)case 1: p=fopen(c:yiban.txt,w);break;case 2: p=fopen(c:erban.txt,w);br

28、eak;case 3: p=fopen(c:sanban.txt,w);break;case 4: p=fopen(c:siban.txt,w);break;doprintf(请输入学生的基本信息,依次输入姓名,学号,性别,籍贯(省名),中间用空格搁开n);scanf(%s %s %s %s,&b.xingming,&b.xuehao,&b.xingbie,&b.jiguan);printf(请输入此学生的成绩(按照数学,英语,线形数学,离散数学,物理,品德,体育的顺序),中间逗号搁开n);scanf(%f,%f,%f,%f,%f,%f,%f,&b.chengji0,&b.chengji1,&

29、b.chengji2,&b.chengji3,&b.chengji4,&b.chengji5,&b.chengji6);b.chengji7=(b.chengji0*3+b.chengji1*3+b.chengji2*2+b.chengji3*2+b.chengji4*2+b.chengji5+b.chengji6*2)/(3+3+2+2+1+2+2);fwrite(&b,sizeof(b),1,p);printf(继续录入请输入1,结束录入请输入2n);scanf(%d,&a);while(a=1);fclose(p);先打开或建立相应的文件,这里需要用户输入要录入的班级,以便把文件分开管理

30、。打开成功后,开始请用户录入信息。信息先存放在一个变量里,然后在一个人的成绩完全输入完成后,直接算出学生的加权成绩,全部存入变量。然后全部写入文件。然后询问用户是否还要继续输入,用户只要输入相应指令,就可以继续或结束输入。查询函数中包括了两种查询方式:学号查询和姓名查询。两个部分大致相同,这里只介绍下其中之一:学号查询.printf(请输入学生的学号n);scanf(%s,&c);while(fread(&d,sizeof(d),1,p)!=0)if(strcmp(d.xuehao,c)=0)printf(姓名,学号,性别,籍贯);printf(%s,%s,%s,%s,d.xingming,d

31、.xuehao,d.xingming,d.jiguan);printf(高等数学一,英语一,线形数学,离散数学,高等物理,思想品德,体育,加权成绩n);printf(%7.1f,%7.1f,%7.1f,%7.1f,%7.1f,%7.1f,%7.1f,%7.1f,d.chengji0,d.chengji1,d.chengji2,d.chengji3,d.chengji4,d.chengji5,d.chengji6,d.chengji7);if(fread(&d,sizeof(d),1,p)=0)printf(查询结束,该班无此人信息n);先由用户输入学生的学号,然后开始读取函数数据。函数数据存放

32、在一个变量p中。用strcmp函数验证是不是两个字符串相同,相同的话就输出这个学生的成绩。后面有个if语句。当没有找到这个学号时就会运行,显示没有找到。查询班级成绩,要函数比较麻烦。因为我把班级的排名也放在这里面,所以代码有些长。但是有大部分跟查询函数类似,下面是排名的函数:for(j=0;j!=0;)j=0;for(k=0;k=40;k+)if(uk.jiaquan=uk+1.jiaquan)m=uk;uk=uk+1;uk+1=m;j+;用的是课本上说的冒泡排序法。当初只是知道了这种思想,自己写出代码后发现与课本上不是太一样,不过功能相同,没有什么差别。实现排名后,只要依次输出各项数据就可以

33、了。调试与运行调试运行的时候自然错误很多,我对他们做了更爱和补救。在编写查询函数时,发现一个问题到现在也没有解决。那就是在获取用户要查找的学生信息时,用gets函数不行。不知道为什么,程序会自动跳过这一句,直接进行下面的语句。到现在也没有弄明白这是为什么,我只好用scanf代替了gets。小结与体会程序因为时间关系没有写完,我很遗憾。本来指导老师告诉我,这个程序太大,建议四人一组共同完成编程任务。可是我没有听,否则应该可以把它写完的。今后不管是学习还是生活,都要重视团队合作的力量。另外在编写过程中发现,一些自认为很简单的问题,自己写起来总是出错。可见古人所说的眼高手低还是有道理的。凡事尤其是编

34、写程序,切记不可在不动手的情况下,低估程序的难度。本人于2008年9月8号在计算机中心6号机房5号机器上完成了本次课程设计。课程设计过程中使用的操作系统是Windows 2000,主要开发平台VC+ 6.0。任务四 黑白棋游戏、任务和意义设计一个程序完成黑白棋,两人对弈。任务分析黑白棋的玩法大家都知道,而要实现一人与电脑对弈的模式牵扯到人工智能方面的知识,远在我的水平之外。所以只好编写两人对弈的模式。开始自己也想过很多,可是后来发现这些都是枉然。这个程序的难度完全超越了我目前的水平。所以把附录上的程序敲入到电脑里。对这已经编好的程序看了好久,由于程序代码太长,而我自己的水平又确实有限,只是看懂

35、了部分代码。关键算法void DrawQp()/*画棋盘*/ int i,j; score1=score2=0;/*棋手一开始得分都为0*/ setbkcolor(BLUE); for(i=100;i=420;i+=40) line(100,i,420,i);/*画水平线*/ line(i,100,i,420); /*画垂直线*/ setcolor(0);/*取消圆周围的一圈东西*/ setfillstyle(SOLID_FILL,15);/*白色实体填充模式*/ fillellipse(500,200,15,15); /*在显示得分的位置画棋*/ setfillstyle(SOLID_FILL,8); /*黑色实

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 研究报告 > 商业贸易


经营许可证编号:宁ICP备18001539号-1