1 输出格式与题目要求不一致
系统自动评分采用的方法主要是黑盒测试,在特定的输入下检查输出结果是否正确。计算机显然没有也很难做到人工阅卷那么灵活,因而对输出格式有一定的要求,有可能程序算法是对的但输出格式不符合要求而导致计算机无法识别而失分,因此程序的输出一定要按照题目的要求进行。
遇到得分不符合预期时,建议检查程序输出的格式是否与题目要求一致,最好使用题目中提供的编程素材、避免无谓的失分——这也是系统提供编程素材的主要目的。
使用编程素材的正确方法是复制、粘贴,既快且准确。这也是系统有意在锻炼和培养考生要灵活地使用复制粘贴,学会既准确、又高效,为以后的工作带来方便。
注意:
(1)不要在程序里自作主张、画蛇添足地输出多余的东西,应严格对照题目中给出的程序运行效果示例进行输出。
(2)程序是否输出了不可见或看不到效果的字符?例如ASCII值为0(刚好也是字符串结束符'\0')、26(文本文件结束符)的字符。若输出了这些字符,由于其不可见,因此程序在屏幕上的输出效果与示例效果、设计预期效果是相同的,但系统在评分时却“看”得见。若仔细检查程序后仍未发现问题且自己的程序跟踪调试能力较差,建议在调试时临时将输出改为每输出一个字符紧接着输出一个下划线(_)字符(如printf("%c"...)改为printf("%c_"...)),看是否有下划线前没有字符的情况。
2 输入格式与题目要求不一致
例如在程序设计题P114中,运行效果示例的输入格式举例为“3000 + 2000”,正确的输入设计应为“scanf("%d %c %d"...)”,但考生则可能设计为“scanf("%d%c%d"...)”并且自己运行时的测试输入为“3000+2000”,结果与题目中的运行效果示例几乎一样,但传到系统中得到的评分结果就是0分——因为评分系统在测试时自动输入的数据格式将类似“3000 + 2000”。
再如在程序设计题P113中,运行效果示例的输入格式举例为“10000,8”,正确的输入设计应为“scanf("%d,%d"...)”,但考生则可能设计为“scanf("%d%d"...)”或“scanf("%d %d"...)”并且自己运行时的测试输入为“10000 8”,结果与题目中的运行效果示例几乎一样,但传到系统中得到的评分结果就是0分——因为评分系统在测试时自动输入的数据格式将类似“10000,8”。
考生在程序的输入设计中偶尔还犯这样的错误:例如在P113中要求先输本金、再输存期,错误设计为先输存期、再输本金;在P740中要求先输money、再输number,错误设计为先输number、再输money。这些都是应当避免的。
因输入格式与题目不一致导致的结果往往表现为:得0分或极少的分,有些情况下评分系统会报告运行出错,例如:
(1)将“scanf("%d %d"...)”写成为“scanf("%d %d\n"...)”,考生的程序因输入无法完成(评分系统只给其输入了正常的数据,例如“1 2”加回车)而始终停留在输入阶段,导致无法正常完成运行。
(2)题目中要求从命令行参数中得到输入,但考生的程序却设计为从键盘输入,在评分时由于评分系统不会从键盘给其输入,考生的程序就始终停留在输入阶段,导致无法正常完成运行。
为了避免输入格式与题目要求不一致,建议考生在输入测试数据时,不要通过键盘逐键敲入,而应将题目中的测试示例数据使用复制、粘贴方式输入给程序,即可发现隐藏的问题,并且既快又准。
3 程序设计有缺陷,或考虑不周
应留意评分系统给出的说明,是哪一方面失分。失分的原因,有可能是:
(1)程序确实考虑不周,有些情况未考虑到,特别是边界条件,考生所谓的“对”往往是测试不全面,只输入了一般的数据进行测试。留意评分系统给出的说明,一般均能发现问题所在。例如,以下代码是计算两个数的平均值、输出时保留两位小数,在设计上是有问题的,但当输入数据为“3,7”时,结果却是对的。顺便提醒:在C语言等数据类型区分较明确的程序语言中,要注意隐含的整除问题,即1/2/与1.0/2的结果是不同的。
int numA, numB;
double avg;
scanf("%d,%d", &numA, &numB);
avg = (numA + numB) / 2;
printf("avg = %.2f\n", avg);
(2)数据计算精度不符合要求。例如求S = 1/1! + 1/2! + 1/3! + … + 1/N!中,当N取值18时,结果应为1.71828182845904553。考生可能算法是对的,但使用的数据类型可能为float型,结果为1.71828162670135498,就要被扣分。
(3)计算结果在数值较小时没有问题,较大时却溢出或越界。例如计算N!,在VC下若用int型变量来存储N!,则13!没有问题,但14!就溢出了——跟踪时不细心可能看不出来,因为1932053504(13!) * 14 = 1278945280,溢出的结果虽然是错的但却是一个正数(溢出的表现并不一定是负数)。
(4)变量的初始化有问题,存在随机、不确定的数据使用,程序的运行结果不稳定、不可靠。例如以下代码,由于max未赋初值,因而其初值是随机的,在VC6下调试时,该程序的结果可能是对的,但换一台计算机调试或使用其发布版本(Release)运行,则结果就可能不对。顺便指出,由于max是在循环中使用,VC6未能给出编译警告提示“local variable 'max' used without having been initialized”。
int i, max, numArr[6]={1, 2, 5, 9, 3, 7};
for (i=0; i<6; i++)
if (max < numArr[i]) max = numArr[i];
printf("max = %d\n", max);
(5)数组越界,在C调试环境下未报错但在服务器上却报错。例如计算f[n] = f[n-1] + f[n-2],n最大取值20,若数组定义不当(如data[20]),则当n输入为20时发生越界(向右),在C调试环境下VC一般未报错(尽管已越界)而隐藏了问题。不能因此去责备VC,VC本身是效率非常高的、用于写操作系统和硬件驱动程序的语言,这正是其效率高的原因和优势,自己不去检查是否越界,Windows系统是否报程序出错要看程序越界本身及导致的连锁反应是否严重,程序内部越界一般只导致程序自己的计算结果出错,只要不最终越界到操作系统给程序划定的内存空间外,则并不影响操作系统的正常运行,操作系统也无法知晓。
在服务器上,评分系统对越界的检查较严格,大家应将其看作一件好事,因为它帮助我们发现了程序的隐患,培养了我们作风严谨、思维严密的习惯并形成一个卓越工程师应当具备的素质,对将来的实际工作大有帮助。
针对该例子,若程序设计不妥,则当n输入为1或0时,说不定也会越界(向左)。
4 程序修改了禁止修改的部分或不符合编程要求
(1)题目要求禁止使用库函数xxxx或使用同名的变量、函数、单词等,但程序中却有违反。部分题目之所以这样要求,并非不提倡使用库函数,而是因为该题本身考察的就是相应库函数的实现或类似实现。
(2)个别题目为了考查相应的知识点,对程序设计作了特别要求,例如要求使用switch,case,default结构,但考生程序中并未如此完成。
(3)出于考查某些知识点、特别是函数的使用与设计,部分试题给出了一部分程序并让考生只能修改允许的部分,该部分很可能有行数和每行长度限制,但程序中却有违反。遇到此种情况,建议使用系统提供的专用检查程序(评分系统会提供下载链接)进行检查。
注意:对于考生添加的某些特殊行,考试系统有较严格的行长度限制,其目的是为了防止不使用函数调用而直接在该行位置以逗号操作符形式写上语句——对应的函数实现的功能很简单、只需少量几条语句。
(4)超过了系统对#include头文件数量的限制,详情请参考“考试系统对每个C程序应包含(#include)头文件的限制”。
对于程序中违反本部分要求的具体情况,评分系统会给出详细的报告。
5 考试系统的编译器不匹配
例如,考生在自己的计算机上使用的是VC 6.0,但在本系统设置(可能是系统默认值或以前设置过)却是TC,由此带来的可能影响请参考“为什么同一程序使用不同的帐号上传到系统后得分不一样?”。
6 编译警告信息未处理或编译警告较宽松
详情请参考“为什么在自己的计算机上程序可以运行,传到系统却说编译有错?——系统对C程序编译警告信息处理的说明”。
对于程序中在这方面存在的问题,评分系统会给出详细的报告。
|