调试,装逼的说就是透过现象看本质。运行结果不对,根据和 预期的差异 猜测判断问题可能在哪。
如果可能太多,就要逐步缩小范围。打印语句,设置断点,输出到文件等等方式。
这就是为什么要 避免滥用全局变量的原因(之一)。全局变量受到的影响太多,被重名变量隐藏,
被某些函数修改(可能是本文件外的函数),这样会增大调试范围,也可能造成难以再现的错误结果,调试的难度大增。
下面这题是USACO section 1.3的calfflac, 在文本中找最长回文。
枚举每个字母作为回文的中心,向两边延伸,直至不相同。
/*
ID: rongxq2
LANG: C
TASK: calfflac
*/
/*
** problem description:
** Input:
read all contents from the given file, and find the longest "palindrome".
** numbers, whitespace, punctuation should be ignored.
Upper case is the same as lower one.
There are at most 20000 chars in a file.
** output the palindrome with number, punctuation, whitespace.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* return the number of bytes read from file */
int readFileToBuf( FILE* fp, char* buf, int limit ){
int c, i=0;
while( ( c=fgetc(fp) )!=EOF && i<limit ){
buf[i++] = c;
}
if( i == limit ) { //buffer is too small
buf[i-1] = '\0';
return limit;
}
buf[i] = '\0';
return i;
}
int main(){
FILE *fin, *fout;
fin = fopen("calfflac.in", "r");
fout = fopen("calfflac.out", "w");
int bufSize=20010, letterTextSize,
i, j,
position[bufSize];
char Text[bufSize],
letterOnly[bufSize];
if( bufSize == readFileToBuf( fin, Text, bufSize ) ){
printf( "buffer too small!\n");
return 0;
}
// preprocess the text, remove useless char and change to lower case
for (i=0, j=0; Text[i]!='\0'; i++ ){
if( isalpha(Text[i]) ){
letterOnly[j] = tolower(Text[i]);
position[j] = i;
j++;
}
}
letterOnly[j] = '\0';
letterTextSize = j;
int mid, left, right, len,
maxL, maxR, maxLen=0;
// odd palindrome
for( mid=0; mid<letterTextSize; mid++){
left = mid; right = mid;
while( left>=0 && right<letterTextSize &&
letterOnly[left] == letterOnly[right]
){
left--;
right++;
}
len = right-left-1;
if ( len > maxLen ){
maxLen = len ;
maxL = left +1;
maxR = right-1;
}
}
// even palindrome
for( mid=0; mid<letterTextSize-1; mid++){
left = mid; right = mid+1;
while( left>=0 && right<letterTextSize &&
letterOnly[left] == letterOnly[right]
){
left--;
right++;
}
len = right-left-1;
if ( len > maxLen ){
maxLen = len ;
maxL = left +1;
maxR = right-1;
}
}
fprintf(fout, "%d\n", maxLen);
for( i= position[maxL]; i<=position[maxR]; i++){
fputc( Text[i], fout );
}
fputc( '\n', fout );
fclose(fin);
fclose(fout);
return 0;
}
输出结果很奇怪,对于比较短的文本(几十字符),输出是对的;对于数百字符的长文本,回文长度是对的,
但是输出的回文牛头不对马嘴。
因为要求输出的是原文本(包含数字,换行之类的),所以要保存原文本和处理之后的纯字母文本 的对应关系。
这个时候可以猜测,在字母文本中回文串是找对了的,但是在找对应原文本时出错了。
这时把找到的回文串先输出来,发现就是正确的。所以猜测 position数组出错了。
打印position。发现居然出现负数,明显是溢出。一看position的类型,是char而不是int。
debug 完毕。
对于重复代码:
两个寻找回文的循环分别是找偶回文和奇回文的。除了left,right初始值不同,其他完全一样。
用一个 while 循环包含那段代码。不过可读性不太好。
odd = 0;
while( odd<2 ){
for(){
left=mid; right = mid+odd;
......
}
}
也可以把那段for循环包装成函数,看起来比较清爽,但是函数参数比较多。