转载
原文标题:《20161116 – 一次DEBUG的小结》
原文链接:http://www.starrylyc.com/wordpress/?p=77
原文作者:Summerfirefly
转载授权:
//本程序目的为去除一段文字开头和每行末尾的 Whitespace //以及单词之间多余的 whitespace,仅保留第一个 whitespace //ECNU OJ Problem 3167 #include <stdio.h> int main() { int i,n; char a[1000],x; i=0; scanf("%c",&x); for (;x==' '||x=='\t'||x=='\n';) scanf ("%c",&x); a[i]=x; i++; while (scanf("%c",&x)!=EOF) { if ((x==' '||x=='\t'||x=='\n')&&a[i-1]!=' '&&a[i-1]!='\t'&&a[i-1]!='\n') { a[i]=x; i++; } if(x!=' '&&x!='\t'&&x!='\n') { a[i]=x; i++; } } if(a[i-1]==' '||a[i-1]=='\t'||a[i-1]=='\n') { i=i-1; a[i]='\0'; } else a[i]='\0'; for (n=0;n<i;n++) printf ("%c",a[n]); return 0; }
以上为一位同学于 20161116 晚发来的一段代码,EOJ 测试 Wrong Answer,本地测试通过(注:这里的本地测试就是本次总结的重点之一)无法理解便交给我,整体 debug 用时一个多小时(注:总结重点之二,debug 的方式要注意)
拿到代码后第一步在 Code::Blocks下进行 debug 测试,用单行数据进行测试,完全无误(事后证明确实无误),用文件重定向在终端模拟OJ的文件测试多行数据,无误,但事后证明这里的测试出现严重的失误,对于可能的输入方式没有考虑完全,导致浪费大量时间
经过长时间的不全面的测试数据进行测试后想到存在如下情况:
Input:
\t\taaaaa aaa\t \t\n
aa a\n
EOF
即多行数据,且非末行的末尾换行符之前连接一串 whitespace,上述错误的代码输出结果为
Output:
aaaaa aaa\taa a\n
显然不正确,本应输出两行,最终只有一行,问题出在Line 19的判断条件上,由于本算法是一次性处理整个文件,而又没有考虑到连续多个空白字符之后紧跟换行符的情况,导致 \t\t\n 这类型序列只存入了 \t 而丢弃了 \n,导致行的缺失,debug 时同样没有注意到这一点,白白浪费大量时间
总结:
- 本地测试时一定要将所有输入的可能性考虑完全
- 考虑可能的输入时一定要结合自己的算法的特点,如本例,由于我自己写的算法是逐行处理,将整个文件作为类似二维的处理,所有换行符都在一行的末尾,因此不存在丢失应有的换行符的问题,但上述代码为整体处理,类似在一维上处理多行文本,换行符不一定在数组末尾。如果仍然按照单行处理的思路,即两个单词之间的 whitespace 只保留第一个,来一次性处理多行文本,就会有丢失换行符的可能性。
Debug 是一项非常重要的技能!非常重要!同时 Debug 的时候一定要注意方法和以前的经验教训,否则将会浪费大量时间。
全面的测试数据将为程序的调试节省大量时间
这题难主要是因为末尾就算有whitespace输出也看不到,所以不如假定n t ‘ ‘是实在的abc,然后输出会比较容易的看出程序问题
@sscjwdyzdw对。所以对于字符串的输出,一种常见的做法是“printf(“#BEGIN#%s#END#”,s);”,这样就会输出形如#BEGIN#Hello,World#END#的结果,一方面可以看到所输出字符串的开始和结束,另一方面便于观察WS。