金月芽期刊網

指針與函數

王立柱

摘 要:

存儲和處理是程序設計的基本矛盾。存儲中也有處理,是基本處理,例如,機器指令中的操作碼,C語言內置類型中的運算符。隨著處理越來越復雜,程序設計的基本矛盾不斷向前發展,從而推動了程序語言的發展。指針(在機器語言中是地址)是存儲和處理的“媒介”、“中介”,是語言的要素,它隨著處理越來越復雜也在同時向前發展。


  存儲和處理是程序設計的基本矛盾。存儲中也有處理,是基本處理,例如,機器指令中的操作碼,C語言內置類型中的運算符。隨著處理越來越復雜,程序設計的基本矛盾不斷向前發展,從而推動了程序語言的發展。指針(在機器語言中是地址)是存儲和處理的“媒介”、“中介”,是語言的要素,它隨著處理越來越復雜也在同時向前發展。
  
  1函數參數與指針
  
  C語言程序是由函數構成的,函數表示處理,實參表示存儲,函數的指針參量表示存儲和處理的中介,實參初始化形參,函數通過指針處理存儲中的數據。以表1為例。
  
  在下面的函數原型中,形參pa的聲明是等價的,都表示指針,都是存儲與處理的中介:
  int Sum(int *pa,int n);
  int Sum(int pa[6],int n);
  int Sum(int pa[],int n);
  
  2模塊化設計與指針
  
  一組存儲中的數據通過傳址在函數之間傳遞。如果這組數據是“只讀”的,那么如何保證它不被改寫?在模塊化程序設計中,程序按模塊編譯,如果在模塊單獨編譯階段就對“只讀”數據的安全性進行控制,即保證“只讀”數據把地址傳給的是“只讀”函數,就會減少連接調試階段的工作負擔。const限定修飾符便是這種控制的工具。
  const限定符既可以限定存儲中的“只讀”數據,也可以限定“只讀”函數。被const修飾的數據稱為const常量,它必須初始化;被const修飾的函數具有被const修飾的指針參量,這個指針稱為指向const常量的指針,表示函數對該指針指向的數據是“只讀”的。const常量的聲明格式為:
  const 類型標識符 變量標識符=初始化數據;
  或
  類型標識符 const 變量標識符=初始化數據;
  指向const常量的指針,其聲明格式為:
  const 類型標識符 *指針變量標識符;
  或
  類型標識符 const *指針變量標識符;
  應用舉例:
   void Display(const int *pa,int n); //終端顯示。“只讀”函數。
  void Selection(int *pa,int n);
   //選擇排序。非“只讀”函數。
   const int a[5]= {1,3,2,5,4};
   //const常量數組。
   int b[5]= {1,3,2,5,4};
   //非const常量數組。
  Selection(a,5); //非法!
  Display(a,5); //合法。
  Selection(b,5); //合法。
  Display(b,5); //合法。
  指針是復合類型,它有兩個值,一個是指針自身的數據(無符號整型值),表示地址,另一個是它指向的數據(指針基類型值),是指針間接引用的對象。const修飾的部分不同,意義不同。
  如果const修飾的是指針指向的數據,那么它是在修飾在修飾函數,表示以該指針為參量的函數對該指針指向的數據是“只讀”的,該指針就是指向const常量的指針。對這樣的指針,有下面幾點需要認識:
  ? 數據無論是不是const常量型,都可以傳址給指向const常量的指針。例如上面的調用語句Display(b,5),其中數組b并不是const常量型的。用實參和形參的關系來表示便是
  const int *pa=b;
  但是const常量型數據只能傳址給代表函數“只讀”性質的指向const常量的指針。可以把帶有指向const常量指針參量的函數比作一個認真辦事的人,什么樣的事情交給他,他都認真處理,而一件需要認真處理的事情一定要交給他。
  ? 因為指向const常量的指針表示的是函數的“只讀”性質,而不是指針本身的數據的只讀性質,所以與const常量不同,這種指針不必初始化。例如:
   const int *pa=b;
  可以分解為
   const int *pa;
   pa=b;
  而且對它本身的數據可以改變,例如:
   const int *pa;
   pa=b; //指向數組b
   pa=a; //又指向數組a
  ? 傳遞性。指向const常量的指針表示的是函數的“只讀”性質,任何數據傳址給這樣的指針,不僅具有這種指針參量的函數對該數據是“只讀”的,而且該函數調用的其它函數對該數據也是“只讀”的,這就是說,指向const常量的指針只能傳值給同類指針。仿佛一個認真辦事的人,什么事情交給他,他都認真處理,不僅如此,他所尋求的合作伙伴,也一定是認真辦事的人。例如:
  void Display(const int*pa,int n); //輸出函數。
  int Sum(const int* ps,int n) //求和函數。
  {
   Display(ps,n); // const int* pa=ps;
   ……
   }
  ? 引入const修飾符之后,任何函數,如果對某一指針參量指向的數據是“只讀”的,都必須把該指針參量限定為指向const常量的指針,表明該函數的“只讀”性質,以保證const常量型數據通過傳址調用該函數,被編譯器檢錯。
  如果const修飾的是指針本身,那么它是在修飾數據,表示指針本身的值const常量型的,這樣的指針稱為const常量指針。與const常量型一樣,const常量指針必須初始化,而且其值不能改變。聲明格式為:
  類型標識符 *const指針標識符=初始化數據;
  例如:
  const int a[5]= {1,3,2,5,4}; //const常量數組。
  int b[5]= {1,3,2,5,4}; //非const常量數組。
  int c[5]= {1,3,2,5,4}; //非const常量數組。
  int *const pc=b; //const常量指針必須初始化。
  pc=c; //非法!const常量指針的值不能改變。
  因為const常量指針不是限定函數,對它指向的數據可以修改,所以不能把const常量型數據的地址賦給const常量指針。例如:
  pc[0]=10; //合法。
  int *const ps=a; //非法。
  
  3運算符函數與指針
  
  3.1運算符函數
  運算符處理的對象如果是語言內置基本類型(整型、浮點型、字符型等),它的意義是內定的。如果是用戶定義的結構,意義就是待定的。以結構數組的查找Find為例:
  struct Student //用戶結構
  {
   long ID; double g; //ID表示學號,g表示成績。
  };
  typedef Student Type; //形式數據類型Type。
  int Find(const Type *pa,int n,Type item)//查找。
  {
   for(int i=0;i   if(pa[i]==item) //待定。
   return(i);
   return(-1);
   }
  陰影部分中的關系運算對象是結構,系統無法確定是比較學號還是比較成績。我們可以進入函數體直接改造:
  if(pa[i].g==item.g)
  
  不過這是權宜之計。結構各式各樣,數組的處理程序數不勝數,都一一改造嗎?這顯然不符合代碼的復用性要求。解決這個問題的方法是運算符重載。
  運算符重載的思路是,首先把以內置類型為處理對象的運算符從觀念上看作函數,然后通過對該函數重載,擴大運算符的操作對象。這樣的函數稱為運算符函數,運算符函數名為operator @,@代表某一種運算符。運算符重載就是運算符函數重載。
  以比較運算符“==”為例,首先把該運算符從觀念上看作一個函數:
  int operator==(int,int);
  于是兩個整數的比較運算表達式
  x==y
  被看作運算符函數的調用
  Operator== (x,y
  然后反過來,重載運算符函數operator==:
   bool operator== (Student a,Student b)//重載運算符函數的定義
   {
   return(a.g==b.g); //比較成績
  }
  重載之后,運算符“==”的處理對象就增加了結構Student。具體的執行過程是,編譯器如果發現內部無法解釋的運算符處理,就會去尋找重載的運算符函數,找到之后,調用這個函數。例如,函數Find中的表達式
   pa[i]==item
  被編譯器替換成
   operator==(pa[i],item)
  運算符重載是函數的一種調用形式。對用戶自定義類型重載的運算符運算,可以等價地表示為運算符函數的調用,但是內部基本類型的運算符運算是內定的,不能實際的替換成運算符函數的調用形式,例如,不能把表達式5==6替換為operator==(5,6)。 ......(未完,請點擊下方“在線閱讀”)
特別說明:本文獻摘要信息,由維普資訊網授權提供,本站只提供索引,不對該文獻的全文內容負責,不提供免費的全文下載服務。

相關文章