程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> static的濫用與變態的閹割

static的濫用與變態的閹割

編輯:關於C語言

什麼情況下需要用局部靜態變量呢?需要保留函數上一次調用結束時的值時,例如可以用下面的方法求n!。
例7.17 輸出1到5的階乘值。

#include <stdio.h>int main( void ){int fac(int n);  int i;  for(i=1;i<=5;i++)    printf("%d!=%d\n" ,i,fac(i) );  return 0;}int fac(int n){static int f=1;  f=f*n;  return(f);}————譚浩強 ,《C程序設計》(第四版),清華大學出版社, 2010年6月,p207

    這段程序的輸出結果是:
    1!=1
    2!=2
    3!=6
    4!=24
    5!=120
    看起來似乎沒有問題,然而稍微仔細思考一下就不難發現,如果若問題再補充一個要求時,比如在求完1到5的階乘後再重新求3的階乘時,那個fac()函數徹底報廢、毫無用處。而造成這種結局的原因則是fac()函數對static莫名其妙的濫用,亦即在不該使用static局部變量時使用了static局部變量。
    為了進一步分析這種寫法的荒謬,下面把fac()函數的內容等價地還原到調用者main()函數中,這樣代碼就變成了

view sourceprint?#include <stdio.h> 

int main( void ) 

  int i; 

  for ( i = 1 ; i <= 5 ; i++ ) 

    { 

     static int f = 1 ;     

     f *= i ; 

     printf("%d!=%d\n" , i , f );  

    } 

  return 0; 

}

    這段代碼與樣本中代碼在功能上是等效的,但卻沒有樣本代碼的毛病。從這段代碼中不難看出代碼段

view sourceprint?for ( i = 1 ; i <= 5 ; i++ ) 

  { 

   static int f = 1 ;     

   f *= i ; 

   printf("%d!=%d\n" , i , f );  

  }

是一個有機的功能整體,其中i的取值順序、static局部變量f及求階乘的運算“f *=i”三者之間互相依賴,唇齒相依。
    樣本代碼的荒謬則在於把緊密依賴、三位一體的東西變態地閹割出一部分來,並把閹割出的部分寫成了只能一次性使用的“殘疾”函數。由於閹割出的部分包含static局部變量,fac()函數的行為對調用次序具有強烈的依賴性,函數就其本性來說根本不應該具有這種嬌生慣養的依賴性。在大多數情況下,只要函數的調用者提供正確的實參,函數都應該產生正確的副效應和返回值,這才是函數的本分。它與調用者之間只應該存在必要的聯系,所謂“必要”就是不多也不少的參數,除此之外不應該再有什麼別的聯系,這就是所謂的“低耦合”的含義。一旦違背了這個原則,比如樣本代碼那樣閹割不可分的功能,就必然導致變態的強耦合聯系方式。在不滿足這種苛刻的強耦合條件下,函數就會變得毫無用處。這就好比把一個完整的計算機主板掰成兩半,再用膠水粘合在一起,擺擺樣子可以,但主板被分開的任何一部分都已經成了廢品。在函數中濫用static局部變量,最終的效果多半如此。
    那麼,是否static局部變量絕對不可以使用呢?倒也不是。但總的來說static局部變量的適應范圍較窄。下面的例子中對static局部變量的使用就非常恰當,無論是把數組name設置為局部還是把它設定為static存儲類別都非常恰到好處。

view sourceprint?#include <stdio.h> 

  

char * month(unsigned) ; 

  

int main( void ) 

  puts( month(10) ); 

  return 0; 

  

char * month(unsigned m)  

  static char * const name[12]  

  = {"Jan","Feb","Mar","Apr","May","Jun", 

     "Jul","Aug","Sep","Oct","Nov","Dec",}; 

  return name[m-1];    

}

摘自:garbageMan

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved