USACO 刷题调试0

3 篇文章 0 订阅
2 篇文章 0 订阅

调试,装逼的说就是透过现象看本质。运行结果不对,根据和 预期的差异 猜测判断问题可能在哪。

如果可能太多,就要逐步缩小范围。打印语句,设置断点,输出到文件等等方式。

这就是为什么要 避免滥用全局变量的原因(之一)。全局变量受到的影响太多,被重名变量隐藏,

被某些函数修改(可能是本文件外的函数),这样会增大调试范围,也可能造成难以再现的错误结果,调试的难度大增。


下面这题是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循环包装成函数,看起来比较清爽,但是函数参数比较多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值