C语言源程序的自动评判毕业设计论文_第1页
C语言源程序的自动评判毕业设计论文_第2页
C语言源程序的自动评判毕业设计论文_第3页
C语言源程序的自动评判毕业设计论文_第4页
C语言源程序的自动评判毕业设计论文_第5页
已阅读5页,还剩95页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

目录第1章引言 11.1背景介绍 11.1.1研究背景简介 11.1.2C语言简介 1第2章概要设计 32.1方案设计 32.1.1开发环境 32.1.2工作方式 32.1.3系统目标 32.2系统功能 32.3需要解决问题 42.4系统流程 42.4.1基本流程 42.4.2具体实现 5第3章详细设计 73.1系统模块化分 73.1.1添加文件对话框 73.1.2编译函数 83.1.3运行/评判对话框 93.2系统模块具体实现 103.2.1准备工作 103.2.2实现添加文件对话框 113.2.3实现编译函数 153.2.4实现运行/评判对话框 19第4章测试 264.1测试方案 264.2运行界面 264.2.1准备系统运行 264.2.2系统测试 27结论 30致谢 32参考文献 33附录A外文参考文献(译文) 34附录B外文参考文献(原文) 48第1章引言1.1背景介绍1.1.1研究背景简介C语言是目前国际上广泛流行的、重要的计算机高级语言之一。它适合作为系统描述语言,即可用来编写系统软件,也可用来编写应用软件。对于学习计算机专业的学生来说,学好C语言将为今后学习其他编程语言打下良好的基础,而随着计算机应用的普及,更多的其他非计算机专业也会需要学习编写简单的程序,C语言也是一个很不错的选择。学习C语言,首先是要学习理论知识,阅读编程思想,阅读源代码,其次就是动手实践上机编写程序了。只有通过自己编写程序,才能更好的掌握理论知识,发现不足,取得进步。传统的教学方式中,学生采用FTP,Email甚至手写的方式提交编程作业,老师一般采用逐一检查并试运行的手工检查方式,然后给出相应的得分。由于在编程作业的提交过程中,很多学生可能会把一些有语法错误以及结果不正确的程序提交上来,这就需要花费老师很多的精力和时间,效果也不是很好。当前,采用计算机对源程序直接进行评判还不是很普遍。因此,有必要开发一套简单易用的C语言源程序的自动评判系统,帮助老师检查学生的编程作业,提高老师工作效率,减轻老师负担。1.1.2C语言简介C语言是国际上广泛流行的、很有发展前途的计算机高级语言。它适合作为系统描述语言,即可用来编写系统软件,也可用来编写应用软件。早期的操作系统等系统软件主要是用汇编语言编写的(包括UNIX操作系统在)。由于汇编语言依赖于计算机硬件,程序的可读性和可移植性都比较差。为了提高可读性和可移植性,最好改用高级语言,但一般的高级语言难以实现汇编语言的某些功能(汇编语言可以直接对硬件进行操作),例如:对存地址的操作、位操作等)。人们设想能否找到一种既具有一般高级语言特性,又具有低级语言特性的语言,集它们的优点于一身。于是,C语言就在这种情况下应运而生了。C语言是在B语言的基础上发展起来的,它的根源可以追溯到ALGOL60。1960年出现的ALGOL60是一种面向问题的高级语言,它离硬件比较远,不宜用来编写系统程序。1963年英国的剑桥大学推出了CPL语言。1967年英国剑桥大学的MatinRichards对CPL语言作了简化,推出了BCPL语言。1970年美国贝尔实验室的KenThompson以BCPL语言为基础,又作了进一步简化,设计出了很简单的而且很接近硬件的B语言,并用B语言写第一个UNIX操作系统,在PDP-7上实现。1971年在PDP-11/20上实现了B语言,并写了UNIX操作系统。但B语言过于简单,功能有限。1972年至1973年间,贝尔实验室的D.M.Ritchie在B语言的基础上设计出了C语言(取BCPL的第二个字母)。最初的C语言只是为描述和实现UNIX操作系统提供一种工作语言而设计的。1973年,K.Thom-pson和D.M.ritchie两人合作把UNIX的90%以上用C改写。后来,C语言多次作了改进,但主要还是在贝尔实验室部使用。直到1-975年UNIX第6版公布后,C语言的突出优点才引起人们普遍注意。1977年出现了不依赖于具体机器的C语言编译文本《可移植C语言编译程序》,使C移植到其它机器时所做的工作大大简化了,这也推动了UNIX操作系统迅速地在各种机器上实现。随着UNIX的日益广泛使用,C语言也迅速得到推广。C语言和UNIX可以说是一对孪生兄弟,在发展过程中相辅相成。1978年以后,C语言已先后移植到大、中、小、微型机上,已独立于UNIX和PDP了。现在C语言已风靡全世界,成为世界上应用最广泛的几种计算机语言之一。C语言主要有以下一些特点:(1)语言表达能力强。(2)语言简洁、紧凑,使用灵活,易于学习和使用。(3)数据类型丰富,具有很强的结构化控制语句。(4)语言生成的代码质量高。(5)语法限制不严格,程序设计自由度大。(6)可移植性好。

第2章概要设计2.1方案设计本课题的任务是完成一个C源程序的自动评判系统。首先需要解决的问题是确定整个系统的开发环境和工作方式,然后是确定系统所要达到的目标,接着分析系统所应完成的功能以及可能遇到的问题,最后给出具体实现的步骤。2.1.1开发环境经过与指导老师的交流,查阅有关资料,分析系统的整体情况,本系统更加类似于一个应用程序,再结合自己所学知识,决定采用微软的VisualC++集成开发环境来开发整个程序。VisualC++是Windows环境下最强大、最流行的程序设计语言之一。VisualC++可以用来开发各种类型、不同规模和复杂程度的应用程序,开发效率很高,生成的应用软件代码品质优良。2.1.2工作方式分析整个系统,最主要的功能是:编译源程序,运行目标程序,目标程序输入输出的重定向。结合VisualC++开发环境来看,有批处理方式、普通应用程序方式、Add-in方式。考虑到Add-in的方式在使用VisualC++编译器去编译C源程序的时候更加方便,并且Add-in的方式也可以利用VisualC++的可视化界面的开发功能,所以工作方式采用VisualC++下的Add-in方式。VisualC++Add-In基本上就是实现了IDSAddIn接口的COM对象。通过这个接口,Add-in能够掌管VisualC++环境,并且执行特定的任务,例如在VisualC++环境下打开工作空间,编译工程等等。在使用Add-in方式的时候,首先需要打开VisualC++环境,然后加载add-in文件(*.dll)。2.1.3系统目标本系统最终目的是为了减轻老师负担,利用计算机自动评判编程作业,替代手工检查方式。要求学生将编写好的作业交至指定文件夹,然后老师运行本系统,编译,运行生成目标程序,通过比较程序输出与标准答案,可以得到每个源程序的评判结果。2.2系统功能详细的分析整个系统功能应该包括:1.从文件夹抽取源程序。2.控制VisualC++编译器编译源程序。3.以测试数据运行生成的目标程序。4.程序输出与标准输出比较。5.根据比较结果得到评判结果。2.3需要解决问题1.存放C源程序的文件夹的组织方式和文件夹中C源程序的命名方式。2.程序通过何种方式提取C源程序。3.用程序控制VisualC++编译器去编译C源程序。4.如何处理编译时出错,没有生成目标程序的C源程序。5.通过何种方式运行编译之后生成的目标程序。6.在运行目标程序时,如何自动完成目标程序的输入和输出。7.对于运行目标程序时异常情况的处理。8.采用何种方式比较输出结果和正确答案,以及如何存储比较结果。2.4系统流程2.4.1基本流程基本上本系统是一个顺序执行的过程,系统的实现也是一步一步来的。下一个模块需要用到上一个模块的数据。系统流程图如图1-1所示。1.系统从文件夹提取出所有的C源程序。2.系统控制VisualC++的编译器去编译提取出的C源程序,得到相应的生成的目标程序(exe)。3.系统以正确输入数据运行生成的目标程序(exe)。4.系统提取运行目标程序(exe)得到的输出数据。5.系统将输出数据与正确答案进行比较。6.根据比较结果得到评判结果。图1-1系统流程图2.4.2具体实现根据系统应该完成的功能,结合需要解决的问题,系统的具体实现如下:1.文件夹的组织方式:每一个题目设置一个文件夹,同一题目的所有编程作业(只交后缀名为*.c的文件)交至对应的唯一文件夹下。2.每个文件夹中C源程序的命名方式:以学号命名,后缀名为*.c,这样每个文件夹中的C源程序是唯一的,在评判时能更直观的得到结果。3.设置一个基本对话框,通过列表控件来提取选择的一个文件夹下的所有C源程序。4.编译方面,VisualC++不能直接编译后缀名为*.c的C源程序,因此提前新建一个WIN32空白工程文件,然后将C源程序的后缀名改为*.cpp,放至空白工程中,便可以解决不能直接编译的问题。通过Add-in接口,控制整个VisualC++环境,打开已放入改了后缀名的C源程序的空白工程文件,然后便可进行编译。在这里要设置循环,对列表框中的每一个C源程序都进行编译。5.循环过程中,编译后生成目标程序的C源程序,从空白工程文件的Debug文件夹中复制其目标程序到暂存的文件夹,并用其学号来命名生成的目标程序。然后循环继续直到所有C源程序都完成编译。6.对于编译后没有生成目标程序的C源程序,视为编译错误,将此结果先一步存至评判结果处。7.编译全部完成后,设置弹出一个对话框,用于输入测试数据、运行正确的目标程序,得到正确答案。同时通过列表框提取已经生成的所有以学号命名的目标程序。8.对于编译正确,已经生成的目标程序,设置循环,每次循环过新建一个进程来运行应用程序,如果程序正常结束,则关闭进程,循环继续去运行下一个目标程序。9.在运行目标程序时,通过管道技术来完成输入输出数据的重定向问题。10.对于目标程序运行时可能出现的种种异常情况,例如死循环等,通过设定一个时间,超出这个时间后进程强制结束来处理,进程强制结束后主循环继续,同时判定为运行时错误。11.在开始循环运行所有目标程序之前,需要老师首先运行此题目正确程序生成的应用程序,并且输入运行数据(如无需数据输入则省略此步骤),得到正确的输出数据,存入一个编辑框。然后每次运行生成的目标程序得到输出时与编辑框中字符串比较,来得到比较结果。结果是相同或是不同。12.最后的评判结果:没有生成目标程序,判为编译出错-50分;生成了目标程序,但是输出与正确答案不同,判为运行错误-60分;生成了目标程序,并且输出结果与正确答案相同,判为程序正确-100分。

第3章详细设计3.1系统模块化分根据系统所应该完成的功能,以及考虑到使用的方便性,将系统划分为三个模块,其中包括两个基本对话框和一个函数。3.1.1添加文件对话框此对话框需要完成的功能、遇到的问题及解决办法:1.初始化:在系统运行之前删除空白工程文件中不需要的文件,清空相关的文件夹。此功能通过对话框上的一个“初始化”按钮完成。在系统运行选择C源程序文之前,需要对相关文件夹和文件进行处理,有删除文件夹、清空文件夹、删除文件。而在VisualC++中是不能直接删除非空的文件夹的,也没有清空文件夹的函数,文件是可以通过库函数DeleteFile()直接删除的。因此这里需要自己添加函数来清空文件夹,在清空文件夹之后调用库函数RemoveDirectory()来删除已空文件夹。2.添加文件:初始化之后,从相应的存放相同题目的文件夹中提取所有的C源程序文件(过滤器设置为只能选取后缀名为*.c的文件),将所有的文件添加至对话框的一个列表控件中,列表控件的每一行项目为C源程序文件的绝对路径。完成添加C源程序后,取得项目总数的信息存入注册表,并且以项目总数设置循环,将每个C源程序文件的绝对路径信息存入注册表,然后调用编译函数。此功能通过对话框的一个“添加文件”按钮和一个列表控件完成。在添加文件时选择用列表控件的方式,这样在之后设置循环对每个C源程序文件进行操作时比较方便。同时每个项目中取的是C源程序文件的绝对路径(包括文件名),因为之后的好多操作需要文件的路径,取得学号信息时也比较方便。因为在Add-in方式下,对话框类和Add-in类之间的数据传递比较特殊,所以采用将列表控件中的相关信息存至注册表的方式,以便今后在编译时调用。3.确认:新建对话框时,默认的代码,无实际功能。通过点击此按钮,得到“OK”按钮按下的消息,调用编译函数。通过对话框的“OK”按钮完成。此对话框的数据输入是:文件夹中选取的所有后缀名为(*.c)的C源程序文件。此对话框的数据输出是:列表控件中的项目总数和列表控件每个项目中C源程序文件的绝对路径。3.1.2编译函数此函数需要完成的功能、遇到的问题及解决办法:编译:从注册表提取出添加文件对话框中列表控件的项目总数,以此设置循环。在每次循环中,首先进行初始化操作,删除空白工程文件夹中相关不用的文件和文件夹,然后通过从注册表提取出添加文件对话框列表控件的项目中的C源程序文件的绝对路径,将后缀名为*.c的C源程序文件改名为与建立空白工程时建立的关联的*.cpp文件。通过Add-in的接口,在VisualC++工作空间打开空白工程文件,此时它已经成为C源程序文件的工程文件,进行编译。编译完成之后如果在空白工程文件的Debug文件夹中找到生成的目标程序,则以此C源程序文件中的学号信息来命名此目标程序(即,此时目标程序改名为学号.exe)并且将改名后的目标程序复制到暂存所有生成的目标程序的文件夹中,以备运行时使用。而如果编译完成之后在空白工程文件的Debug文件夹中没有找到生成的目标程序,则视为编译错误,直接在结果文件夹中以学号为信息给出评判结果。处理结束后进行下一个循环直到循环结束,给出编译已完成的信息提示框。首先编译时取用的数据是刚才添加文件对话框中列表控件中添加入注册表的信息。在每次循环开始前,都需要对test文件夹进行处理,删除Debug文件夹,删除0.cpp文件,清空result、outcome文件夹,这些问题同添加文件对话框问题中的初始化一样,都需要自己编写函数来清空文件夹和删除非空文件夹。然后因为是将C源程序文件加入空白工程文件中编译,且空白的关联cpp文件已经命名为0.cpp,所以C源程序文件在编译前都需要改名为0.cpp文件。之后通过Add-in,控制整个VisualC++的开发环境,首先打开工作空间,然后载入工程,之后编译,当然这些都是VisualC++自动完成的,相当于按下了Build按钮,这也就是使用Add-in方式的关键所在。编译结束后,如果在Debug文件夹中生成0.exe文件,则视为编译成功,且此时需要将此文件转移出来,因为如不转移,编译下一个C源程序文件时会覆盖此0.exe文件。此函数的数据输入是:列表控件中的项目总数和列表控件每个项目中C源程序文件的绝对路径。此函数的数据输出是:编译成功后以学号命名的存至相同文件夹下的目标程序;编译错误后以学号为区分信息的存至结果文件夹下的评判结果。3.1.3运行/评判对话框此对话框需要完成的功能及其解决办法:1.输入数据、运行正确程序:弹出此对话框后,进入运行目标程序,评判阶段,首先运行此题目正确程序编译后生成的exe程序,如果需要输入数据才能运行的,先输入数据,得到此题目正确的输出。此功能通过“选择正确程序”按钮来选择此题目正确程序生成的exe文件,通过一个编辑框显示运行的正确exe文件路径,通过另一个编辑框来实现数据输入,通过第三个编辑框来得到运行正确exe文件后得到的数据输出,即标准答案。在编译结束后,进入运行/评判阶段,首先需要运行正确的程序,这是老师之前通过编译正确题目程序得到的正确的exe程序。如果程序需要输入数据之后运行的,在“正确输入”编辑框中输入正确数据。通过编辑框的方式输入数据方便直观。因为这里是老师输入正确程序的正确数据输入,所以老师会确保输入数据的正确性。而如果不需输入数据即可得到输出数据的话就不用输入数据即可。之后通过CreateProcess()函数运行正确程序,这里通过重定向技术使用管道来完成自动的使用输入数据运行程序并且自动的将输出数据送入编辑框而不是在显示屏显示。在正确输出编辑框中会显示出正确的结果,这样子也便于观察。2.选择目标文件:输入正确数据,以此数据运行正确的exe文件后,得到正确输出,即标准答案。选取暂存文件夹中所有C源程序文件编译正确后生成的所有以学号命名的目标程序至列表控件,列表控件项目为选取的目标程序的绝对路径。此功能通过一个“添加文件”完成选取所有目标程序,通过一个列表控件来完成添加所有目标文件。这里也是通过列表控件来完成选择文件的工作,因为知道生成的所有目标程序在test文件夹下的result文件夹中,所以在打开文件时直接定位到此程序所在的文件夹。每个项目中同样也是放的目标程序的绝对路径(包括文件名),因为之后使用函数运行程序是需要使用程序的绝对路径。3.运行目标文件、进行评判:完成选取所有目标程序后,以列表控件的项目总数即目标程序总数设置循环。在每次循环中,以运行正确程序的exe文件时的数据输入作为运行目标程序的数据输入,即使用正确输入编辑框中的输入数据,去运行目标程序,得到输出数据,将此输出数据与正确输出编辑框中的数据比较,这两个数据都是CString类型的。如果比较结果相同,则视为运行正确,将此结果以学号信息为区别存至结果文件夹中作为评判结果;如果比较结果不同,则视为运行时错误,也将此结果以学号信息为区别存至结果文件夹作为评判结果。完成一个目标程序的运行、评判之后,循环继续,去运行、评判下一个C源程序。直到处理完所有的目标程序,至此运行、评判结束。此功能通过一个“开始”按钮完成。在这里运行程序时的原理和运行正确程序时的一样,正确的数据输入就采用正确输入编辑框中的数据,这样可以确保程序正确时得到的输出与正确输出相同,方便评判。一个问题是需要考虑到这里运行的是学生的程序而不是老师的正确程序,所以可能出现运行异常、死循环的进程不结束的问题,那么就会出现死机的情况,主程序运行不下去,所以这里需要设置进程运行超时的处理。因为是教学中的C源程序文件作业,相对较为简单,所以设置运行时间为4秒,如果进程运行超时还没有自动结束,则强制结束,判为运行时错误。若果进程自动结束,则于正确结果比较得到评判结果。此对话框的数据输入是:题目正确源程序生成的exe文件,正确的测试数据输入,所有C源程序文件编译正确后生成的目标程序。此对话框的数据输出是:以输入的正确测试数据运行正确程序后的正确数据输出;比较运行目标程序后的数据输出与正确数据输出,结果相同后得到的以学号信息区别的存至结果文件夹的运行正确的评判结果;比较运行目标程序后的数据输出与正确数据输出,结果不同后得到的以学号信息区别的存至结果文件夹的运行错误的评判结果。3.2系统模块具体实现在这一节中,将会对各个模块中系统那个实现的难点、遇到的问题、解决的方法、重点技术问题的给出详细的说明。3.2.1准备工作在开始系统设计之前,在VisualC++中新建一个Win32空白工程,这里工程名为test,然后在此空白工程中新建一个C++文件,文件名为0.cpp。以后编译选取的C源程序文件时则将C源程序文件改名为0.cpp并替换空白工程中的0.cpp文件即可。为防止编译时编译两次,选择组件->配置,移除Win32Release只保留Win32Debug。在此空白工程文件夹test中,新建一个文件夹result用于保存编译成功后生成的以学号命名的目标程序,新建一个文件夹outcome用于存放最后的评判信息,新建一个空白文本文件file.txt。在每次开始使用系统之前,进行的初始化操作就包括删除Debug文件夹、删除0.cpp文件,清空result和outcome文件夹。接着开始系统的具体功能实现阶段。首先VisualC++中新建一个DevStudioAdd-inWizard工程,工程名称为Auto,并且在CCommands->ICommands中自动添加一个函数AutoCommandMethod()。这个函数是系统的切入点。这时编译工程之后,生成DLL文件,加载此文件后,工具栏会添加一个按钮,此按钮实现的是AutoCommandMethod()的函数功能。系统的使用从点击这个按钮开始。3.2.2实现添加文件对话框建立起DevStudioAdd-inWizard工程后,在工作空间,右击AutoClasses添加一个对话框类AddFile,即添加文件对话框。编辑此对话框,添加“初始化”、“添加文件”按钮和一个列表控件,保留默认的“OK”、“Cancle”按钮。1.“初始化”按钮:此按钮完成的功能是删除Debug文件夹、删除0.cpp文件,清空result和outcome文件夹。在VisualC++中可以通过库函数DeleteFile()删除一个文件。(1).在此遇见的问题是在VisualC++中不能直接删除一个不为空的文件夹以及没有现成的库函数来清空一个文件夹,因此自己添加两个函数DeleteFolder和ClearFolder,分别用于删除文件夹(不管其是否为空)和清空文件夹(清空其中的文件而保留文件夹),函数代码如下:a.DeleteFolder函数voidAddFile::DeleteFolder(CStringsPath){CFileFindff;BOOLbFound;bFound=ff.FindFile(sPath+"\\*.*");while(bFound){bFound=ff.FindNextFile();CStringsFilePath=ff.GetFilePath();if(ff.IsDirectory()){if(!ff.IsDots())DeleteFolder(sFilePath);}else{if(ff.IsReadOnly()){SetFileAttributes(sFilePath,FILE_ATTRIBUTE_NORMAL);}DeleteFile(sFilePath);}}ff.Close();SetFileAttributes(sPath,FILE_ATTRIBUTE_NORMAL);RemoveDirectory(sPath);}b.ClearFolder函数voidAddFile::ClearFolder(CStringsPath){CFileFindff;BOOLbFound;bFound=ff.FindFile(sPath+"\\*.*");while(bFound){bFound=ff.FindNextFile();CStringsFilePath=ff.GetFilePath();if(ff.IsDirectory()){if(!ff.IsDots())DeleteFolder(sFilePath);}else{if(ff.IsReadOnly()){SetFileAttributes(sFilePath,FILE_ATTRIBUTE_NORMAL);}DeleteFile(sFilePath);}}ff.Close();SetFileAttributes(sPath,FILE_ATTRIBUTE_NORMAL);}(2).完整的“初始化”按钮代码如下:{CStringStrDestFile="D:\\test\\0.cpp";DeleteFile(StrDestFile);//删除0.cpp文件CStringDirectoryDebugName="D:\\test\\Debug";DeleteFolder(DirectoryDebugName);//删除DEBUG文件夹 CStringDirectoryResultName="D:\\test\\result";ClearFolder(DirectoryResultName);//清空result文件夹ClearFolder("D:\\test\\outcome");//清空outcome文件夹 GetDlgItem(IDC_addfile_BUTTON)->EnableWindow(true);//设置“添加文件”按钮禁用,点击“初始化”后启用GetDlgItem(IDOK)->EnableWindow(true);// 设置“OK”按钮禁用,点击“初始化”后启用}2.“添加文件”按钮:点击之后弹出选择文件对话框,完成选择所有的C源程序文件,然后将所有的C源程序文件添加至对话框的列表控件中,列表控件的每一行项目为C源程序文件的绝对路径。然后将列表控件中的项目总数和每个项目所指向的C源程序文件的绝对路径存入注册表,以备编译时使用。(1).列表控件的初始化工作需要首先设置列表控件的属性属性->样式->查看->报告,然后在AddFile类的Message中选择WM_INITDIALOG添加函数OnInitDialog(),最后在此函数中添加代码如下:m_list.InsertColumn(0,"file",LVCFMT_CENTER,500,-1);(2).点击“添加文件”按钮后弹出打开文件对话框,通过CFileDialog来实现,设置过滤器以便只能选择后缀名为*.c的C源程序文件,同时相关参数设置为能够选择多个文件,其代码如下:CFileDialogDlg(TRUE,"*.c",NULL,OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT,"C文件(*.c)|*.c|",NULL);(3).对于选择多个文件添加至列表控件中,需要设置指针,通过GetStartPosition()函数使指针指向选取的第一个文件开始,直至最后一个文件,然后通过GetNextPathName()函数来将选取的C源程序文件的绝对路径添加入列表控件,代码如下:POSITIONpos=Dlg.GetStartPosition();while(pos!=NULL){CStringFileName="";FileName=Dlg.GetNextPathName(pos);m_list.InsertItem(0,"",0);m_list.SetItem(0,0,LVIF_TEXT,FileName,0,0,0,0);}(4).将选取的所有C源程序文件的绝对路径存入列表控件后,通过AfxGetApp()->WriteProfileInt将列表框项目总数写入注册表,然后以项目总数设置循环,通过AfxGetApp()->WriteProfileString依次将每个C源程序文件的绝对路径写入注册表,以备编译时使用,其代码如下:AfxGetApp()->WriteProfileInt("Configure","count",m_list.GetItemCount());for(inti=0;i<m_list.GetItemCount();i++){ charszRegKey[50]; wsprintf(szRegKey,"%d",i); AfxGetApp()->WriteProfileString("Configure",szRegKey, m_list.GetItemText(i,0));}(5).完整的“添加文件”按钮代码如下:{ CFileDialogDlg(TRUE,"*.c",NULL,OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT,"C文件(*.c)|*.c|",NULL); if(Dlg.DoModal()==IDOK){POSITIONpos=Dlg.GetStartPosition();while(pos!=NULL) {CStringFileName="";FileName=Dlg.GetNextPathName(pos);m_list.InsertItem(0,"",0); m_list.SetItem(0,0,LVIF_TEXT,FileName,0,0,0,0); } AfxGetApp()->WriteProfileInt("Configure","count",m_list.GetItemCount()); for(inti=0;i<m_list.GetItemCount();i++) { charszRegKey[50]; wsprintf(szRegKey,"%d",i); AfxGetApp()->WriteProfileString("Configure",szRegKey, m_list.GetItemText(i,0)); }} }3.“OK”按钮:此按钮的代码是新建对话框时的默认代码,无实际功能,其按下的意义在于,取得按下“OK”的消息,调用编译函数。此消息的实现是在系统切入点AutoCommandMethod()函数出,点击工具栏按钮后弹出添加文件对话框,进行完选取C源程序文件的操作后,点击“OK”按钮,AutoCommandMethod()函数得到按下“OK”按钮的消息,然后调用编译函数,进入下一步工作,这里AutoCommandMethod()函数相关代码如下:AddFileAddFileDlg;//弹出添加文件对话框if(AddFileDlg.DoModal()==IDOK)//若按下添加文件对话框的“OK”按钮{ build();//调用编译函数}3.2.3实现编译函数首先建立编译函数,这个函数是在Add-in方式下建立的,目的是操控VisualC++的开发环境,实现在工作空间打开工程文件,调用VisualC++自带的编译器去编译工程。建立此函数的过程是:右击CCommands类下的ICommands,选择AddMethod,然后方法名称为build,即建立了一个build()函数,此时函数代码为空,不实现功能。在添加文件对话框完成所有工作后,点击“OK”按钮,发出按钮按下的消息,在AutoCommandMethod()函数中调用build()函数。此函数要实现的功能是:1.初始化工作,在每次编译C源程序文件前需要删除Debug文件夹和o.cpp文件,以保证编译成功后在Debug文件夹中生成的目标程序是对应当前的C源程序文件的,其代码如下:DeleteFile("D:\\test\\0.cpp");//删除0.cpp文件DeleteFolder("D:\\test\\Debug");//删除Debug文件夹2.取得C源程序文件中的学号信息,因为C源程序文件存至列表控件中的是其绝对路径,包括路径和完整的文件名(因为在命名时有要求,所以文件名也就是“学号.c”),所以需要提取出文件名中的学号(即文件标题),学号是唯一区别标志,以便在给出评判结果时使用学号信息,代码如下:CStringstillfilename;CStringfiletitle;CStringStrFile=AfxGetApp()->GetProfileString("Configure",RegKey,"");//获取文件路径和完整文件名stillfilename=StrFile.Right(StrFile.GetLength()-StrFile.ReverseFind('\\')-1);//获取文件名,带后缀 filetitle=stillfilename.Left(stillfilename.ReverseFind('.'));//获取文件标题(学号),即文件名去掉后缀3.取得注册表中存入的添加文件对话框中列表控件的项目总数和每个项目中选取的C源程序文件的绝对路径,并以项目总数设置循环。每次循环中首先进行初始化操作,然后将C源程序文件改名为o.cpp文件并复制到空白工程test文件夹下。新打开一个工作空间,打开此时的test工程文件(test.dsw),最后编译此工程文件。(1).取得项目总数,并以此设置循环的代码如下:intnNumWorkspaces=AfxGetApp()->GetProfileInt("Configure","count",0);for(intnWorkspaceNumber=nNumWorkspaces;nWorkspaceNumber>=1;nWorkspaceNumber--)(2).改名复制C源程序文件,新建工作空间,打开工程文件,编译的代码如下:longlCount;charRegKey[50];wsprintf(RegKey,"%d",nWorkspaceNumber-1);CStringStrDestFile="D:\\test\\0.cpp";CopyFile(StrFile,StrDestFile,false);//拷贝并改名C文件至空白工程CComBSTRbszWorkspacePathName="D:\\test\\test.dsw"; CComPtr<IDispatch>pDispDocuments;VERIFY_OK(m_pApplication->get_Documents(&pDispDocuments));CComVariantOleVariant;CComQIPtr<IDocuments,&IID_IDocuments>pDocuments(pDispDocuments);CComPtr<IDispatch>pWorkspace; VERIFY_OK(pDocuments->Open(bszWorkspacePathName,OleVariant, OleVariant,&pWorkspace));CComPtr<IDispatch>pDispProjects; VERIFY_OK(m_pApplication->get_Projects(&pDispProjects));CComQIPtr<IProjects,&IID_IProjects>pProjects(pDispProjects);VERIFY_OK(pProjects->get_Count(&lCount)); for(longi=1;i<lCount+1;i++) { longlNumConfigs; CComVariantVari=i; CComPtr<IGenericProject>pGenProject; VERIFY_OK(pProjects->Item(Vari,&pGenProject));CComQIPtr<IBuildProject,&IID_IBuildProject>pProject(pGenProject); CComPtr<IConfigurations>pConfigs; VERIFY_OK(pProject->get_Configurations(&pConfigs)); VERIFY_OK(pConfigs->get_Count(&lNumConfigs)); for(longj=1;j<lNumConfigs+1;j++) { CComVariantVarj=j; CComPtr<IConfiguration>pConfig; VERIFY_OK(pConfigs->Item(Varj,&pConfig)); CComVariantVarDisp=pConfig; CComBSTRbszStr; VERIFY_OK(pConfig->get_Name(&bszStr)); VERIFY_OK(m_pApplication->Build(VarDisp)); } }(3).在循环中遇到的问题是每次打开一个工作空间并对工程进行编译后没有关闭文档,从而使每次开始新循环后无法实现删除Debug文件夹和o.cpp文件,造成目标程序永远是对应第一个C源程序文件的,解决的办法是在编译结束后关闭文档,即工作空间,代码如下:DsSaveStatusd;VARIANTvtSaveChanges;vtSaveChanges.lVal=dsSaveChangesNo;vtSaveChanges.vt=VT_I4;VERIFY_OK(pDocuments->CloseAll(vtSaveChanges,&d));4.每次循环中,编译结束后,关闭工作空间,在空白工程test文件夹中的Debug下,如果能找到生成的目标程序test.exe文件,则视为编译正确,将此test.exe文件复制到暂存目标程序的result文件夹,并改名为以学号命名的exe文件,即学号.exe文件,作为此C源程序文件编译成功生成的目标程序。而如果编译结束后,在Debug文件夹中没有找到生成的目标程序test.exe文件,则视为编译错误,复制空白的文本文件file.txt并改名为以此C源程序文件的学号命名的“学号-编译错误-50”文本文件,作为评判结果存至结果文件夹outcome。这一部分代码如下:CFileFindfind;CFileFindfindexe;if(find.FindFile(exefile)){ CopyFile(exefile,"D:\\test\\result\\test.exe",false);{if(findexe.FindFile("D:\\test\\result\\test.exe")) { CStringnewexefile="D:\\test\\result\\"+filetitle+".exe"; MoveFile("D:\\test\\result\\test.exe",newexefile); } }}else{ CStringerrorfile;CStringfile="D:\\test\\file.txt";errorfile="D:\\test\\outcome\\"+filetitle+"编译错误-50"+".txt";CopyFile(file,errorfile,false);}5.编译完所有的C源程序文件,在result文件夹中存储所有编译成功后得到的以学号命名的目标程序,在outcome文件夹中存储所有编译错误没有得到目标程序的以学号为区别信息的评判结果之后,弹出消息提示框,提示编译已经结束,点击确认进入运行/评判对话框。代码如下:CStringStrInfo="编译连接结束,点击进行运行评判";if(AfxMessageBox(StrInfo,MB_YESNO)==IDYES) { runRunDlg;//这里run是建立的运行/评判对话框的类名 RunDlg.DoModal(); }3.2.4实现运行/评判对话框调用编译函数,对所有的C源程序文件进行编译,处理生成的目标文件,并且先一步给出编译不正确的C源程序文件的评判结果后,弹出运行/评判对话框。这就首先需要在工作空间,右击AutoClasses添加一个对话框类run,即添加运行/评判对话框。编辑此对话框,首先添加一些必要的用于说明性的静态文本,再添加编辑框一用于显示运行的正确的exe程序绝对路径;编辑框二用于输入运行正确程序的输入数据,此数据也用于作为运行所有生成的目标程序的输入数据;编辑框三用于输出运行正确exe程序后的正确输出结果,并且在运行所有的目标程序得到输出结果后与此编辑框中的正确输出结果比较以得到评判结果。另外,添加一个列表控件,添加一个“选择正确程序”按钮,一个“运行正确程序”按钮,一个“选择文件”按钮,保留默认的“OK”按钮和“Cancle”按钮。1.“选择正确程序”按钮:在开始选择C源程序文件之前,需要老师先在VisualC++下运行一次题目正确的程序,得到正确的exe程序。之后点击这个按钮,弹出选择文件对话框,设置过滤器为只能选择exe文件,然后选择正确的exe文件,并在编辑框中显示出其绝对路径。代码如下:CFileDialogDlg(TRUE,"*.exe",NULL,OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT,"可执行文件(*.exe)|*.exe|",NULL); if(Dlg.DoModal()==IDOK){ CStringStrFileName=Dlg.GetPathName();GetDlgItem(IDC_exe_EDIT)->SetWindowText(StrFileName); GetDlgItem(IDC_run_BUTTON)->EnableWindow(true);}2.“运行正确程序”按钮:在选择了题目正确的exe程序之后,在相应的正确输入编辑框输入数据,以此数据来运行正确的exe程序,而如果程序是不需要数据输入运行后直接得到数据输出的,则也省略掉数据输入这一步。在运行正确的exe程序时,利用CreateProcess()函数来新建一个进程运行exe程序,因为是正确的程序,所以这里不设置进程运行超时强制结束。关于输入、输出数据的重定向问题,通过建立两个管道来解决,输入数据取正确输入编辑框中的数据,输出数据输出到正确输出编辑框。其代码如下:SECURITY_ATTRIBUTESsa,sa2;HANDLEhInputRead,hInputWrite;HANDLEhRead,hWrite;sa.nLength=sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor=NULL;sa.bInheritHandle=TRUE;CreatePipe(&hRead,&hWrite,&sa,0); sa2.nLength=sizeof(SECURITY_ATTRIBUTES);sa2.lpSecurityDescriptor=NULL;sa2.bInheritHandle=TRUE;CreatePipe(&hInputRead,&hInputWrite,&sa2,0); STARTUPINFOsi;PROCESS_INFORMATIONpi;si.cb=sizeof(STARTUPINFO);GetStartupInfo(&si);si.hStdError=hWrite;si.hStdOutput=hWrite;si.hStdInput=hInputRead;si.wShowWindow=SW_HIDE;si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;DWORDdwWritten;UpdateData(TRUE);CreateProcess(m_exeEdit,NULL,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi);CloseHandle(hInputRead);CloseHandle(hWrite);UpdateData(TRUE);CStringput=m_inEdit+"\\n";//输入框输入数据,类型为CStringcharszInPut[20];memcpy(szInPut,put,20);//将CString类型数据输入到char中WriteFile(hInputWrite,szInPut,strlen(szInPut),&dwWritten,NULL);charbuffer[4096]={0};DWORDbytesRead;while(true){if(ReadFile(hRead,buffer,4095,&bytesRead,NULL)==NULL)break;m_outEdit+=buffer;UpdateData(false);Sleep(200);}GetDlgItem(IDC_add_BUTTON)->EnableWindow(true);3.“选择文件”按钮:此按钮的作用是在得到正确输出数据后,点击此按钮,弹出选择文件对话框,选择所有C源程序文件编译正确后生成的以学号命名的目标程序。由于这些文件都存放在result文件夹下,所以选择文件时直接定位至result文件夹,并且将选择的所有目标程序加入列表控件。列表控件的每个项目显示的是目标文件的绝对路径。列表控件的初始化工作与添加文件对话框中的列表控件相同。其代码如下:CFileDialogDlg(TRUE,"*.exe",NULL,OFN_FILEMUSTEXIST|OFN_ALLOWMULTISELECT,"可执行文件(*.exe)|*.exe|",NULL); Dlg.m_ofn.lpstrInitialDir="D:\\test\\result";if(Dlg.DoModal()==IDOK){POSITIONpos=Dlg.GetStartPosition();while(pos!=NULL){CStringFileName="";FileName=Dlg.GetNextPathName(pos);m_exelist.InsertItem(0,"",0);m_exelist.SetItem(0,0,LVIF_TEXT,FileName,0,0,0,0);}} GetDlgItem(IDOK)->EnableWindow(true);4.“OK”按钮:在将C源程序文件编译正确后生成的所有目标程序加入列表控件后,取得列表控件项目总数,以此设置循环,每次循环中进行对一个目标程序进行如下操作:(1).首先从对应目标程序的绝对路径中取得文件名去掉后缀后的标题,即学号信息,作为之后给出评判结果时使用。代码如下:CStringfilepath=m_exelist.GetItemText(i,0);CStringfilename=filepath.Right(filepath.GetLength()-filepath.ReverseFind('\\')-1);CStringfiletitle=filename.Left(filename.ReverseFind('.'));//获取文件标题,文件名去掉后缀,即得到学号信息(2).通过CreateProcess()函数来新建一个进程运行目标程序,运行结束后自动关闭进程。通过管道技术,建立两个管道来实现输入、输出数据的重定向问题。以正确输入编辑框中的数据作为输入数据运行目标程序,如果无需数据输入则视为输入为空;将运行后得到的数据存入一个字符串中。其代码如下:CStringoutcome;SECURITY_ATTRIBUTESsa,sa2;HANDLEhInputRead,hInputWrite;HANDLEhRead,hWrite;sa.nLength=sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor=NULL;sa.bInheritHandle=TRUE;CreatePipe(&hRead,&hWrite,&sa,0); sa2.nLength=sizeof(SECURITY_ATTRIBUTES);sa2.lpSecurityDescriptor=NULL;sa2.bInheritHandle=TRUE;CreatePipe(&hInputRead,&hInputWrite,&sa2,0); STARTUPINFOsi;PROCESS_INFORMATIONpi;si.cb=sizeof(STARTUPINFO);GetStartupInfo(&si);si.hStdError=hWrite;si.hStdOutput=hWrite;si.hStdInput=hInputRead;si.wShowWindow=SW_HIDE;si.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;DWORDdwWritten;UpdateData(TRUE);CreateProcess(m_exeEdit,NULL,NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi);CloseHandle(hInputRead);CloseHandle(hWrite);UpdateData(TRUE);CStringput=m_inEdit+"\\n";//输入框输入数据,类型为CStringcharszInPut[20];memcpy(szInPut,put,20);//将CString类型数据输入到char中WriteFile(hInputWrite,szInPut,strlen(szInPut),&dwWritten,NULL);charbuffer[4096]={0};DWORDbytesRead;while(true){if(ReadFile(hRead,buffer,4095,&bytesRead,NULL)==NULL)break;outcome+=buffer;Sleep(200);}(3).为防止运行时出现死循环等异常情况,设置进程的运行时间为4秒,超时则强制结束进程,且判为错误。如果有输出数据能存入字符串outcome,则将outcome与正确输出编辑框的正确输出比较。如果结果相同则视为运行正确,复制空白的文本文件file.txt并改名为以此目标程序对应的C源程序文件的学号命名的“学号-运行正确-100”文本文件,作为评判结果存至结果文件夹outcome。如果结果不同则视为运行时出错,复制空白的文本文件file.txt并改名为以此目标程序对应的C源程序文件的学号命名的“学号-运行错误-60”文本文件,作为评判结果存至结果文件夹outcome。其代码如下:if(outcome!="") { if(outcome==m_outEdit) {CStringrightfile="D:\\test\\outcome\\"+filetitle+"运行正确--100"+".txt"; CopyFile("D:\\test\\file.txt",rightfile,false);} else {CStringerrorfile="D:\\test\\outcome\\"+filetitle+"运行错误--60"+".txt"; CopyFile("D:\\test\\file.txt",errorfile,false);} }else { DWORDEvent;Event=WaitForSingleObject(pi.hProcess,4000);if(Event=WAIT_TIMEOUT) {DWORDexitcode=0; TerminateProcess(pi.hProcess,exitcode); CStringerrorfile="D:\\test\\outcome\\"+filetitle+"运行错误--60"+".txt"; CopyFile("D:\\test\\file.txt",errorfile,false); }//如果进程没有自动终止,4秒钟后自动关闭,并给出评判结果*/ }最后给出消息提示框,提示评判结束,点击确认后退出,代码如下:MessageBox("运行结束,请查看结果");CDialog::OnOK();完成系统的详细设计之后,对系统进行测试,同时演示出运行时的界面,给用户以直观的使用帮助。

第4章测试4.1测试方案鉴于本系统的目的是用于评判教学中学生编写的C源程序文件,程序的复杂度不是很高,输入输出数据也相对较为简单。所以测试数据取两组,一组的题目无需数据输入,运行后直接得到数据输出;一组的题目需要输入数据运行后才能得到输出数据。将这两组数据以唯一序号命名,存入两个不同的文件夹。为了测试出各种质量的程序的评判结果是否正确,分别选取各文件夹中的一个程序修改使之存在语法错误而无法通过编译,选取另一个程序修改使之语确能够通过编译但输出容与正确输出不同。在运行这两个题目正确的C源程序得到正确的exe文件后,开始进入测试。4.2运行界面4.2.1准备系统运行由于系统采用了VisualC++的Add-In方式,所以在开始使用系统前,需要加载程序开发编译后生成的DLL文件。选择VisualC++菜单栏中“工具”->“定制”->“附加项和宏文件”->“浏览”,在弹出的选择文件对话框中首先选择文件类型为Add-ins(.dll),然后找到Auto工程文件夹下Debug文件夹中的Auto.dll文件,打开,如图4-1所示,此时定制对话框中显示已加载了dll文件。图4-1加载dll文件成功点击“关闭”后,在VisualC++开发环境的工具栏中显示添加了一个新的按钮,如图4-2所示此按钮即是系统的开始使用按钮,所谓Add-In的方式,也就是把程序功能嵌入到VisualC++开发环境中。图4-2工具栏添加按钮4.2.2系统测试1.添加文件对话框点击此工具栏中按钮,弹出添加文件对话框,点击“初始化”,启用“添加文件”、“OK”按钮。点击“添加文件”,选择测试文件夹下的所有测试程序,这里先使用需要输入数据的源程序。添加完成后,如图4-3所示,并点击“OK“按钮。图4-3添加文件2.点击“OK”按钮后,关闭添加文件对话框,调用编译函数build(),系统自动进行编译部分的工作,结束后弹出信息提示框,如图4-4所示,点击“是(Y)”后进入运行/评判对话框。图4-4编译结束信息提示框3.进入运行/评判对话框后,首先点击“选择正确程序”按钮,选则之前生成的正确的exe程序,然后输入正确的输入数据,这里用数字333。再点击“运行正确程序”,在正确输出编辑框得到正确的数据输出。测试程序的目的是计算一个三位数的各个位数上的数字之和,所以这里的重定向后正确输出为:Pleaseimportanumber:Thesumis:9再点击“选择文件”,选择result文件夹下的所有目标程序添加至列表控件,最后点击“OK”按钮,运行这些目标程序并且进行评判。因为文件205.c设置的是语法错误,无法通过编译,所以在目标程序中没有205.exe文件,如图4-5所示。图4-5选择正确程序,输入数据后运行,得到正确输出,再添加目标程序运行/评判结束后,弹出信息提示框,提示所有评判工作已经完成,点击“是(Y)”后,退出运行/评判对话框,这样再点击工具栏按钮便可以进行下一条题目的评判。信息提示框如图4-6所示。图4-6评判结束信息提示框最后,在outcome文件夹中可以查看评判结果,结果是一个个与C源程序文件对应的空白文本文件,文件名是对应的评判信息。空白处右击->查看->详细信息,便可以直观的得到评判信息了。结果如图4-7所示。图4-7评判结果经过检查,评判的结果与预先设置的文件质量相同,能够区分出编译错误,运行错误和运行正确。在测试另一组无需数据输入题目的C源程序文件后,结果也正确。

结论经过设计、开发、测试,整个系统得以实现。首先整个系统在VisualC++开发环境下能够通过加载DLL文件顺利开始运行。在C语言源程序题目需要数据输入和无需数据输入的两种情况下,都可以完成对于C语言源程序的基本评判工作,能够结合学生上交题目的学号给出相应的直观明了的评判结果,减轻老师负担。整个系统的运行过程力求操作最简,按照顺序和提示一步一步进行最简单的点击、输入等各种,即可以完成对于大量C源程序文件的评判各种。最终完成的系统达到了预期的目标。在整个系统的开发过程中,遇到的技术难点有三个。第一就是Add-in的开发方式,这是之前完全没有接触过的一个方式,不同于一般的对话框方式。这个方式在变量的调用,函数的调用方面都具有自身的特点,例如平时使用的MessageBox()函数,在Add-in方式下需改为AfxMessageBox(),这些难点是参考MSDN中的相关说明后基本解决。第二个就是对于编译成功后得到的目标程序如何运行,在VisualC++中运行一个exe程序有多种方法,例如可以通过ShellExecute()、WinExec()来运行,但是考虑到需要在运行时重定向输入输出数据,最后决定通过新建一个进程来运行目标程序,即使用CreateProcess()函数来运行。第三个问题是关于如何在运行目标程序时重定向输入输出,即如何自动的载入输入数据和将输出数据重定向到一个字符串中以方便和正确答案比较,最后这个问题是通过使用通道来解决。通过这次毕业设计的过程,让自己在各方面得到提高。首先,大大增加了自己对于编程的兴趣。其次,使自己更加熟悉的C语言、C++语言,以及VisualC++的开发环境,学习了以前没有深入学习过的知识。第三,提高了自己解决自己之前未接触过的问题的能力,通过请教老师、同学,系统而深入的研究MSDN,网上查找资料等等方式,在解决遇到的各种问题时,都是行之有效的方法。第四,提高了自己攥写论文的能力,系统开发出来,还要能够说明自己开发的整个过程,从接到任务到完成任务。第五,提高了自己对于软件工

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论