C语言初学者代码中的常见错误与瑕疵(1)

时间:2022-03-04 08:13:08

  曾在豆瓣上看到过一个小朋友贴出他自己的代码(http://www.douban.com/group/topic/40293109/),当时随口指点了几句。难得这位小朋友虚心修正、从善如流,不断地改,又不断地贴,坚持了很久。到后来这位小朋友的代码已经大有长进。

  这位小朋友犯过的很多错误都非常典型,在初学者中非常普遍,于是整理了一下,应该对其他初学者有借鉴意义。

问题

开灯问题

  有n盏灯,编号为1~n,第1个人把所有灯打开,第2个人按下所有编号为2 的倍数的开关(这些灯将被关掉),第3 个人按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),依此类推。一共有k个人,问最后有哪些灯开着?输入:n和k,输出开着的灯编号。k≤n≤1000

代码:

 #include <stdio.h>
#include <math.h> int main()
{
int a[],n,k,i,j; printf("请分别输入灯和人的数量\n");
scanf("%d%d",&n,&k); while() //检验是否超出
{
if(k>= && k<= && n>=k && n<=)
break;
else
{
printf("数值不符,请重新输入:\n");
scanf("%d%d",&n,&k);
}
} for(i=;i<=k;i++) //每操作一次第i*j个开关,a[i*j]加1
{
for(j=;i*j<=n;j++)
{
a[i*j]=a[i*j]+;
}
} for(i=;i<=n;i++) //若操作次数为偶数,表示该位置的灯亮着
{
if(a[i]%== && a[i]!=)
printf("%d\t",i);
} printf("\n");
return ;
}

测试:

“自己测了觉得没问题..在线系统结果是WrongAnswer ..未找出原因..”

评:

  最明显的错误就是第26行

a[i*j]=a[i*j]+;

由于前面定义a数组为局部auto类别,在不进行初始化的情况下,a中的数据是垃圾值。换句话说,a中的数据是无意义的。因此a[i*j]+1这个表达式没有意义。

  此外,第22行

  for(i=;i<=k;i++) //每操作一次第i*j个开关,a[i*j]加1

在逻辑上也是错误的,缺乏“第1个人把所有灯打开”的步骤。

  另外

   printf("请分别输入灯和人的数量\n");
scanf("%d%d",&n,&k); while() //检验是否超出
{
if(k>= && k<= && n>=k && n<=)
break;
else
{
printf("数值不符,请重新输入:\n");
scanf("%d%d",&n,&k);
}
}

  这段写得很丑,属于典型的谭浩强风格,C语言应该这样写:

printf("请分别输入灯和人的数量\n");
while(scanf("%d%d",&n,&k) ,( k < || n<k || n>) )
{
printf("数值不符,请重新输入:\n");
}

  代码中还有其他一些毛病,由于不是最主要的问题,这里就不再进一步指出了。

重构:

#include <stdio.h> 

#define MAXNUM 1000
#define ON 0
#define OFF 1 int main( void )
{
int light[MAXNUM] = { ON } ; //把所有灯打开
int n , k ;
int i ; printf( "请分别输入灯和人的数量\n" );
while ( scanf("%d%d", & n ,& k ) ,( k < || n < k || n > MAXNUM ) )
printf("数值不符,请重新输入:\n"); for ( i = - ; i < k ; i ++ ) //第2个人按下所有编号为2 的倍数的开关……
{
int j ;
for ( j = i ; j < n ; j += i + )
light[j] = ! light[j];
} for ( i = ; i < n ; i ++ )
if( light[i]==ON )
printf( "%d " , i + );
putchar('\n'); return ;
}