關於程序風格的一點討論。



   到目前爲止,我們已經瞭解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 ) );//以一維指針遍歷二維數組。
最後,我還是得說,這裏寫的東西只是筆者兩年來的一些心得,不合適之處, 不要採納,大家可以去讀一本鉅作《程序設計實踐》。比我說這些要好上百倍。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章