经常有小伙伴在瑞格系统刷题的时候发现,如果利用判断一行输入的结束符作为条件来控制程序时,会发生和本机上不一致的情形。今天统一做一说明。话不多说,上例子:
首先申明,这个题目的完成是在学习数组之前,如果学习完字符数组,利用gets语句来完成数据的输入,这个题目就不涉及今天所说的问题了。
由于还没有学习数组,所以本题目只能用char 类型变量c来循环接收各个字符,并统计各类字符的个数,代码如下:
- #include <stdio.h>
- #include <stdlib.h>
- int main()
- {
- char c;//用来循环接收输入的字符
- int numa,num1,numsp,numqt;
- //上面变量分别表示字母个数,数字个数,空格个数,其他字符个数
- numa=num1=numsp=numqt=0;
- while(1)
- {
- c=getchar();
- //printf("%c %dn",c,c);
- if(c=='r' || c=='n' ||c==EOF) break;
- //line14中if语句中的条件涉及到这行字符的结束符,下面具体讲解
- else if(c>='A' && c<='Z' || c>='a' && c<='z') //字母字符
- numa++;
- else if(c>='0' && c<='9') num1++;//数字字符
- else if (c==' ') numsp++; //空格字符
- else numqt++;//其他字符
- }
- printf("%d %d %d %d",numa,num1,numsp,numqt);
- return 0;
- }
有的小伙伴一看到字符序列,就认定这个字符序列是一行字符,认为只要用c==‘n'来作为结束字符就可以了,把line 14写为:
if(c=='n') break;
提交代码后,反馈结果为:
这说明程序中存在死循环,也就是说测试数据中可能没有回车符,这样就没有办法结束循环。
那就对14行做如下修改是否可以呢?
if(c==EOF) break;
提交后结果显示:
也就是说其他字符多了4个,看来有的测试数据中还包括换行符。因此,仅仅用EOF作为结束判断,可能会把换行符作为其他字符进行处理。因此需要把换行符作为结束条件,14行改为:
if(c=='n' ||c==EOF) break;
提交后,反馈结果为:
同样显示,其他字符多了一个,那多统计了哪个字符呢?
这个问题就涉及到瑞格系统中验证程序正确与否时的输入和输出重定向问题。瑞格系统中程序从输入文件中获取测试数据,打印输出则重定向到一个输出文件中。在文件中存储的测试数据的格式可能有多种有不同的情况,例如只有字符,最后没有换行(如“abcd122”);也可能最后有换行,甚至之后还有若干个空行如下图所示,光标在第三行,也就是说输入数据是三行,包括两个空行。
具体是哪种可以用line 13行的代码测试一下。
(1)利用line 13行代码测试5476题目,反馈结果为:
这说明在5476的测试数据文件中,只有“5+9”三个字符,没有后面的换行符。
(2)将上面的代码输入5477,反馈结果为:
这说明在5477的测试数据文件中题目中说明的用一个空格分隔的两个字符(三个字符)如“c d”后有换行,后面还有两个空行。也就是说,这个输入数据文件中共有三行,第一行有三个字符后加换行符。后面又有两个空行。此时,细心的小伙伴发现了,空行是用两个字符表示的。怎么回事呢?
在键盘中测试时,一行字符的结尾是ASCII为10的'n';而瑞格系统上输入文件中的换行是两个字符:一个是ASCII值为13的'r',另一个是ASCII值为10的'n'。
因此,上面的代码在瑞格上提交的时候出现问题就是很容易理解的了,在瑞格上'n'符号前还有一个'r'字符,因此如果题目中有一个空行的话,就会把'n'前的'r'作为其他字符统计了。因此,还应该把'r'也作为结束条件。那为什么还保留c=='n'呢?这是为了在本机的Codeblocks里面调试准备的,因为本机上是用n来作为行结束符的呀。
PS. EOF:End Of File,也就是说getchar()和scanf()函数在读取输入数据时,文件中没有数据可读时,会返回-1,为了便于理解,我们定义了一个宏,EOF,它表示的值为-1.注意,不是文件的结尾有一个符号是EOF,而是当读取文件的时候,读到最后一个数据,再往后读就没有数据了,为了返回这种状态,就用-1来进行表示。getchar()返回字符的ASCII值,所有字符的ASCII值都大于等于0,scanf()函数返回成功赋值的个数,因此,这个数也都大于等于0.因此,-1可以表示这种特殊状态.