关于程序风格的一点讨论。
到目前为止,我们已经了解c程序的基本元素,在进入过程化程序设计之前,我个人认为该对编码习惯做个良好的开端。关于程序设计风格问题,严格来说是一个没答案的讨论,随着编码经验的增加,我们在不同的阶段会有不同的认识,不同的出发点,本文要说的也只是笔者了两年来的编码体会,写出来的确需要勇气(毕竟在很多人眼里我没有这个资格),只是讨论的目的,绝无要误人子弟之意。
一个好的程序员写出来的代码不仅要让机器运行起来并实现想得到结果,而且要让任何一位懂c语言的人看了就明白这段代码是什么意思,而不是需要大量的注释和文档来帮助他搞懂你的意思(当然作为辅助还是必须的)。以下就是个人的一些体会:
第一:合理利用空白字符,使得代码风格简洁清楚。像下面这段代码,实在让人看起来费劲;
#include “stdio.h”
#include “stdlib.h”
int main()
{
int a[2][1],i,j;
for(i=0;i<2;++i)
for(j=0;j<1;++j)
scanf("%d",&a[i][j]);
for(i=0;i<2;++i)
for(j=0;j<1;++j)
printf("%d",a[i][j]);
system("pause");
return 0;
}
当然,习惯在IDE下编写代码的朋友们可以借助环境的自动缩进(在非windows环境下往往就没这么舒服,得自己手动缩进),让上面的东西稍微好一点:
#include “stdio.h”
#include “stdlib.h”
int main()
{
int a[2][1],i,j;
for(i=0;i<2;++i)
for(j=0;j<1;++j)
scanf("%d",&a[i][j]);
for(i=0;i<2;++i)
for)j=0;j<1;++j)
printf("%d",a[i][j]);
system("pause");
return 0;
}
但是,看上去还是有点乱,特别是表达式的写法,如果你是telnet环境下的bbs里看这段代码对于眼睛来说不能不说是场恶梦。于是我们在运算符和括号的里恻各加个空格。并将不同意义的变量分开定义,哪怕他们属于同一类型。
#include “stdio.h”
#include “stdlib.h”
int main()
{
int a[ 2 ][ 1 ];
int i, j;
for( i = 0; i < 2; ++i )
for( j = 0; j < 1; ++j )
scanf( "%d", &a[ i ][ j ] );
for( i = 0; i < 2; ++i )
for( j = 0; j < 1; ++j )
printf( "%d", a[ i ][ j ] );
system( "pause" );
return 0;
}
呵呵。别看只是几个空格的问题。当你的代码很长的时候它可以帮助你让别人有耐心读下去,如果一眼看去符号字母集成一堆,谁还有兴趣看呢?
第二:尽量分解问题,多写函数,简化main函数。比如上面那段代码可以写成下面这样,你会觉得更容易理解代码的功能、
#include “stdio.h”
#include “stdlib.h”
const int* scan( int *p )
{
int i, j;
for( i = 0; i < 2; ++i )
for( j = 0; j < 1; ++j )
scanf( "%d", ( p + j ) + i * 2 );
return p;
}
void print( const int *p )
{
int i, j;
for( i = 0; i < 2; ++i )
for( j = 0; j < 1; ++j )
printf( "%d", *( ( p + j ) + i * 2 ) );
}
int main()
{
int a[ 2 ][ 1 ];
print( scan( &a[ 0 ][ 0 ] ) );
system( "pause" );
return 0;
}
当然。对于实现细节来说,是更复杂化了。但是我们看一眼main函数就知道这是在干什么.。而对于我们的用户来说需要知道的往往只是接口,函数的细节通常被隐藏起来。因此上面的代码写在同一文件中是不合适的。这个关系到设计模式的问题。这里不再多说了。朋友们可以去看看《设计模式》这本书。
第三:尽量使用有意义的符号名字,少用无意义的符号和幻数。在上面的例子中函数的名字使得我们对它的功能一目了然,但是这段代码还是有些麻烦,大家都知道数组越界是个要不得的错误,因此我们用循环测它。但是2这个数字意思非常不明白,时间一长。程序一复杂我们就会搞不明白这个2是干嘛的,因此我们得用宏替代它,经过修改,把这些代码写成单文件如下所示(再次说明,单文件不是好的选择,这里只是为了显示方便):
#include “stdio.h”
#include “stdlib.h”
#define SIZE_1 2
#define SIZE_2 1
const int* fun1( int *p )
{
int i, j;
for( i = 0; i < SIZE_1; ++i )
for( j = 0; j < SIZE_2; ++j )
scanf( "%d", ( p + j ) + i * 2 );
return p;
}
void fun2( const int *p )
{
int i, j;
for( i = 0; i < SIZE_1; ++i )
for( j = 0; j < SIZE_2; ++j )
printf( "%d", *( ( p + j ) + i * 2 ) );
}
int main()
{
int array[ SIZE_1 ][ SIZE_2 ];
fun2( fun1( &array[ 0 ][ 0 ] ) );
system( "pause" );
return 0;
}
用SIZE_n来表示每一维的长度,使得我们不再解释循环中2、1从何而来。
第四:注释。对于一些难以一下就理解的语句我们可以用注释辅助理解,但是个人认为注释不能写的太多,一方面你要信任你用户的能力,他们都是比笔者更好的程序员。我们只要在变量和函数的名字中稍加暗示,他们就可是理会你的意思,但对于一些自己看起来不太清楚的,估计在日后可能会引起麻烦的代码,必须加注释说明你的意思。
比如对于这句代码。我不敢肯定指针的遍历是否正确,则我必须注释说明
printf( "%d", *( ( p + j ) + i * 2 ) );//以一维指针遍历二维数组。
最后,我还是得说,这里写的东西只是笔者两年来的一些心得,不合适之处, 不要采纳,大家可以去读一本巨作《程序设计实践》。比我说这些要好上百倍。
本文首载第二书店