最近才刚开始接触OJ,用的是九度OJ,在使用C/C++编程过程中我遇到了很多问题,下面就将这些问题总结出来,对我是一种提醒,希望也能借我的总结帮助到其他刚接触OJ并且被很多问题困扰的人。
1.宏定义最好在定义的时候加括号,要么就在使用的时候加括号,遇到百思不得其解的程序运行时,可以考虑是否有宏定义没加括号引起程序出错,这是一个非常隐蔽的错误。举个例子吧,看下面代码:
#define ISYEAP(x) x%4==0 && x%100!=0 || x%400==0 ? 1:0
int
main()
{
int d,m,y;
int sum;
char s[20];
while( scanf("%d%s%d",&d,s,&y)!=EOF ){
sum=0;
for( m=1;m<=12;m++ ){
if(strcmp(s,MonthName[m])==0)
break;
sum+=DayofMonth[m];
}
sum=sum+d;
if(m>2)
sum=sum+(ISYEAP(y));/*如果写成sum=sum+ISYEAP(y);结果sum的值就变了,就是因为括号的问题*/
puts(WeekDay[((y-1)+(y-1)/4-(y-1)/100+(y-1)/400+sum)%7]);
}
return 0;
}
2.程序中即使找不到语句的错误也不代表能通过评测,有时可能是输出的字符串的
字母、大小写、是否要换行等问题出现,经常是在输出时需要在输出要求内容的同时在最后输出一个换行符‘\n’,否则程序多组测试数据之间因为缺少换行出错。
3.使用C++提供的库函数(如sort)的时候要注意要遵循C++的风格,在引入相应头文件之后需要使用using
namespace
std;
来使用标准命名空间,否则会出现找不到函数的错误。
4.变量初始化的问题,尤其是数组元素,使用前一定要初始化,而且对于每次循环都要初始化的情况应该将初始化语句放在循环开头。
5.程序空行的问题,要求每次的结果输出之间要空行,一般使用的方法是在程序主要代码执行完之后加空行,但是会导致最后一组输出完之后多输出一个空行,为避免此类情况,应使用如下代码:
bool IsFirst=true;
while( scanf("%d %c %c",&n,&a,&b)!=EOF ){
if( IsFirst==true )
IsFirst=false;
else
printf("\n");
/*
**code section
*/
}
这样,在只输入一组数据的时候就不会添加空格,多一组数据在之前加空格。
5.程序要求要仔细阅读,比如叠筐问题:把一个个大小差一圈的筐叠上去,使得从上往下看时,边筐花色交错。(http://ac.jobdu.com/problem.php?pid=1432)
输入是一个个的三元组,分别是,外筐尺寸n(n为满足0
输出叠在一起的筐图案,中心花色与外筐花色字符从内层起交错相叠,多筐相叠时,最外筐的角总是被打磨掉。叠筐与叠筐之间应有一行间隔。
11 B A 5 @ W
AAAAAAAAA ABBBBBBBBBA ABAAAAAAABA ABABBBBBABA ABABAAABABA ABABABABABA ABABAAABABA ABABBBBBABA ABAAAAAAABA ABBBBBBBBBA AAAAAAAAA @@@ @WWW@ @W@W@ @WWW@ @@@
判断输出字符的语句为:
char
ch=( i%2==0?a:b );
因为从外层循环每次判断都是以最外层为准,从外向内依次是字符a,b,a,b,……,而要求是从内往外依次是a,b,a,b,……,因此改为:
char
ch=( (round-i)%2==0?a:b );
6.字符串使用char[ ]类型定义时,为保证可能达到的字符数,应该将字符数的值设置大一些,比如定义如下结构体:
typedef struct Student
{
char number[100];
char name[100];
char sex[5];
int age;
}Student;
刚开始时我将姓名字符串定义为char name[20];结果OJ一直显示Wrong Answer!仔细检查最终才发现这个地方出问题了,很隐蔽,一定要注意!
7.由于OJ采用多组数据多次试验程序,所以在使用到数组、栈、队列等数据结构的时候要在while(scanf("%d",&n){之后立即考虑将这些数据结构初始化,没有初始化的话可能会导致之前的数据对之后的运行造成影响导致最终程序出错。
8.指针传递的指针值单向性问题,指针传递是可以改变指针指向的对象的内容,但在传递之后不能不能改变传递的指针值,在需要传址的情况下保持原对象在函数调用中更新有两种方法,一个是传递指针给函数,在函数中用return语句返回新的指针值,这在C语言中是常见的(你可能会想既然已经传址了,不就应该同步吗,其实不然,同步的是传递指针指向的对象的值而非指针值,比如说传递二叉树的根节点指针,在调用删除根结点的函数中就会将根节点内存空间释放,此时这个时候新的根结点的地址并不能自动传递回去,因此需要使用return语句返回根结点地址,这个问题也是我遇到返回时访问根结点时出现指针值为0xfeeefeee,此值的含义为: 此指针指向的位置已经被释放了, 但释放后,又错误的重新调用了这个无效指针,我这才想到指针传递的指针值单向性问题),另一种方式是在函数中声明传递对象的引用(即在函数形参声明时在*后面加上&,如Node *A变为Node *&A),这样对引用的操作就直接传递到了传递对象中。下面分别是两种方式的例子:
方式一:使用return返回:(二叉排序树的插入)
Node *Insert( Node *T,int x ){
if( T==NULL ){
T=(Node *)malloc(sizeof(Node));
T->lchild=NULL;
T->rchild=NULL;
T->c=x;
return T;
}
else if( x < T->c )
T->lchild=Insert( T->lchild,x );
else if( x > T->c )
T->rchild=Insert( T->rchild,x );
return T;
}
void Delete( Node *&T ){
if( T->rchild==0 ){
Node *p=T;
T=T->lchild;
free( p );
}
else if( T->lchild==0 ){
Node *p=T;
T=T->rchild;
free( p );
}
else{
Node *p=T,*s=T->lchild;
while( s->rchild ){
p=s;
s=s->rchild;
}
T->c=s->c;
if( p!=T )
p->rchild=s->lchild;
else
p->lchild=s->lchild;
free( s );
}
}
void DeleteBST( Node *&T,int x ){
if( x==T->c )
Delete(T);
else if( xc )
DeleteBST( T->lchild,x );
else
DeleteBST(T->rchild,x );
}
9.