1. 程式人生 > >C++ Primer Plus 筆記第七章

C++ Primer Plus 筆記第七章

處的 進入 code pri name 結束 show 素數 設置

復習函數基本知識:

  要使用C++函數,要完成工作:

     1. 提供函數基本知識;

     2. 提供函數原型;

     3. 調用函數

   庫函數是已經定義和編譯好的函數,同時可以使用標準庫頭文件提供其原型

     eg:標準頭文件 cstring 中包含了 strlen() 和其它一些字符串相關的函數原型

函數原型和函數調用:

   函數原型描述了函數到編譯器的接口,將函數返回值的類型及參數類型和數量告訴編譯器;

   double cube ( double x );   or  double cube ( double );   

   原型的功能:

    編譯器正確處理函數返回值;

    編譯器檢查使用的參數數目是否正確;

    編譯器檢查使用參數類型是否正確,如果不正確,轉換為正確的類型(可能的話)

函數和數組:

  int sum_arr ( int * arr,int n ) // 數組的元素為 int 型,因此 正確的函數頭傳遞參數為 int * arr

  int sum_arr ( int arr[ ],int n ) // 用 int arr[ ] 替換 int * arr ,含義相同。同時 int arr[ ] 還提醒用戶 arr 不僅指向 int 而且是指向數組的第一個 int

   在大多數情況下,C++和C語言一樣,將數組名視為指針,存在兩種例外:

    1. 數組聲明,使用數組名來標記存儲位置;

    2. 對數組名使用 sizeof 將得到整個數組的長度

   函數傳遞數組時,將數組的位置(地址)、包含的元素種類(類型)以及元素的數目(n變量)提交給函數;

   函數傳遞常規變量時,函數將使用變量的拷貝,但使用數組時,函數使用原來的數組;

   可以在被傳遞函數中,數組參數使用 const 限定符,保證原始數組數據不被修改(只讀傳入)

    int show_array ( const double arr[ ],int limit ); // 函數原型

鍵盤輸入數組並顯示輸入數組例程:

 1 #include<iostream>
 2
using namespace std; 3 int fill_array(double ar[], int limit); 4 void show_array(const double ar[],int n); // const 可以防止修改數組內容 5 6 int main() 7 { 8 const int arsize = 5; 9 double ar[arsize]; 10 int n; 11 n = fill_array(ar, arsize); // 數組調用,將數組的首地址作為實參 12 //cout << n<<endl; 13 show_array(ar, n); 14 } 15 16 // 輸入數組 17 int fill_array(double ar[], int limit) 18 { 19 double res; 20 int i; 21 for ( i = 0; i < limit; i++) 22 { 23 cout << "Enter value #" << i + 1 << ": "; 24 while (!(cin >> res)) // 判斷是否正確讀入數字,如果沒有,進入循環 25 { 26 cin.clear(); // 重置輸入,如果省略,程序將拒絕繼續讀取輸入 27 while (cin.get() != \n) // 清除輸入流中所有的錯誤輸入到‘\n‘ 28 continue; 29 cout << "wrong! please enter number: \n" 30 << "Enter value #" << i + 1 << ":"; 31 } 32 if (res < 0) // 負值輸入將提前結束數組的輸入 33 break; 34 ar[i] = res; 35 } 36 return i; 37 } 38 // 顯示數組 39 void show_array(const double ar[], int n) 40 { 41 for (int i = 0; i < n; i++) 42 cout << ar[i] << endl; 43 }

自下而上的程序設計:

   通過數據類型和設計適當的函數來處理數據,然後將這些函數組合成一個程序;

   適合於OOP——它首先強調的數據表示和操縱

使用數組區間的函數:

   對於處理數組的C++函數,必須將處理數組中的種類、數組的起始位置和數組中元素數量交給函數:

    1. 將數組的起始處的指針作為一個參數,將數組的長度作為第二個參數;

    2. 指定元素區間,通過傳遞兩個指針完成,一個標識數組開頭,一個標識數組尾部

   eg:

    sum = sum_arr ( arr, arr+3 ); // 函數調用,實參傳入地址區間

    int sum ( const int* begin,const int* end );// 函數頭,形參為兩個指向數組類型的指針(int*)

指針和 const:

   可以使用兩種不同的方式將 const 關鍵字用於指針:

    1. 讓指針指向一個常量對象,防止使用該指針修改所指向的值;

    2. 將指針本身聲明為常量

   聲明一個指向常量的指針:

    int age = 39;

    const int * pt = &age;

    聲明中 pt 指向一個 const int 因此不能使用 pt 修改這個值—— *pt 為常量不能修改

   還可以將 const 變量的地址賦給指向const的指針,不能將 const 的地址賦給常規的指針

   記住:如果數據類型不是指針,可以將 const 數據或非 const 數據的地址指向 const 指針

      不能將 const 數據賦給非 const 指針

   int * const finger = &sloth:

    指針 finger 本身被聲明為 const,使得 finger 只能指向 sloth,但允許使用 finger 來修改 sloth 的值

函數和二維數組:

   數組作為參數的函數,數組名被視為地址,相應的形參應為一個指針;

   int data[3][4] = { {1,2,3,4}, {9,8,7,6}, {2,4,6,8} }; // 聲明

   int tatal = sum(data, 3); // 調用

   兩種函數原型(形參的形式):

     int sum (int (*ar2) [4],int size ); // 聲明一個由4個指向 int 的指針組成的數組,括號不能省

     int sum (int ar2[ ][4],int size); // 可讀性更強

   在函數定義中使用二維數組,最簡單的辦法是將 ar2 看作一個二維數組的名稱

   ar2 實際上是一個指針,必須對 ar2 執行兩次解除引用才能得到數據:

    最簡單的方式:ar2[r][c];

    ar2[r][c] = *(*(ar2 + r) + c); // same thing

函數和C-風格字符串:

   將字符串作為參數時意味著傳遞的是地址;

   表示字符串的方式有3種:

    1. char 數組

    2. 用引括號起的字符串常量

    3. 被設置為字符串的地址的 char 指針

   將字符串作為參數來傳遞,實際傳遞的是字符串的第一個字符的地址,形參聲明應為 char*:

    int c_in_str (const char * str,char ch); // 使用指針表示法

    int c_in_str (const char str[],char ch); // 也可以使用數組表示法

   處理字符串中字符的標準方式:

1 while (*str)        // until *stt == ‘\0‘
2 {
3     statement;
4     str++      // 將指針增加一個字節 
5 }

返回C-風格字符串的函數:

   函數無法返回一個字符串,但是可以返回字符串的地址;

   char * buildstr ( char c,int n )

函數和結構:

   為結構編寫函數比為數組編寫函數簡單,結構變量相比於數組更接近於單值變量;

   函數可以使用原始結構的拷貝,也可返回結構(因為結構可以互相賦值);

   結構名只是結構的名稱,要獲得結構的地址,必須使用地址操作符 &;

處理結構的函數例程:

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 struct polar {
 6     double distance;
 7     double angle;
 8 };
 9 struct rect {
10     double x;
11     double y;
12 };
13 polar rect_to_polar(rect xypose);
14 void show_polar(polar rrpose);
15 int main()
16 {
17     polar rppose;
18     rect xypose;
19     cout << "Enter pose x and y or type ‘q‘ to quiz: ";
20     while (cin>>xypose.x>>xypose.y)
21     {
22 
23         rppose = rect_to_polar(xypose);
24         show_polar(rppose);
25         cout << ("Continue Enter x and y or type ‘q‘ to quiz: ");
26 
27     }
28     return 0;
29 }
30 
31 polar rect_to_polar(rect xypose)
32 {
33     polar rppose;
34     rppose.distance = sqrt(xypose.x*xypose.x + xypose.y*xypose.y);
35     rppose.angle = atan2(xypose.y, xypose.x);
36     return rppose;
37 }
38 
39 void show_polar(polar rppose)
40 {
41     const double rad_to_deg = 57.29577951;
42 
43     cout << "distance = " << rppose.distance << endl;
44     cout << "angle = " << rppose.angle*rad_to_deg << " degrees\n";
45 
46 }

傳遞結構地址例程:

   與傳遞結構本身不同之處:

    1. 調用函數時,將結構地址(&pplace)而不是結構本身(pplace);

    2. 將形參聲明為指向 polar 的指針,即 polar* 類型;

    3. 形參指針而不是結構,因此應使用間接成員操作符(->)而不是(.);

    4. 傳遞地址而不是復制,函數可能不在需要返回值,使用 void

 1 #include<iostream>
 2 #include<cmath>
 3 using namespace std;
 4 
 5 struct polar {
 6     double distance;
 7     double angle;
 8 };
 9 struct rect {
10     double x;
11     double y;
12 };
13 void rect_to_polar(const rect * xypose, polar* rppose);
14 void show_polar(const polar * rppose);
15 int main()
16 {
17     polar rppose;
18     rect xypose;
19     cout << "Enter pose x and y or type ‘q‘ to quiz: ";
20     while (cin >> xypose.x >> xypose.y)
21     {
22 
23         rect_to_polar( &xypose, &rppose );
24         show_polar( &rppose );
25         cout << ("Continue Enter x and y or type ‘q‘ to quiz: ");
26 
27     }
28     return 0;
29 }
30 
31 void rect_to_polar(const rect* xypose, polar * rppose)
32 {
33     rppose->distance = sqrt(xypose->x*xypose->x + xypose->y*xypose->y);
34     rppose->angle = atan2(xypose->y, xypose->x);
35 }
36 
37 void show_polar(const polar * rppose)
38 {
39     const double rad_to_deg = 57.29577951;
40 
41     cout << "distance = " << rppose->distance << endl;
42     cout << "angle = " << rppose->angle*rad_to_deg << " degrees\n";
43 
44 }

函數和 string 對象:

   C++如果需要多個字符串,可以聲明一個 string 對象數組,而不是二維 char 數組;

   以下例程聲明了一個 string 對象數組,並將該數組傳遞給一個函數以顯示其內容:

 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 const int SIZE = 5;
 5 void display(const string list[], int n);
 6 
 7 int main()
 8 {
 9     string list[SIZE];    // 聲明 string 數組,每一個元素為一個 string 對象
10     cout << "Enter your " << SIZE << " favotite astronomical sights: \n";
11     for (int i = 0; i < SIZE; i++)
12     {
13         cout << i + 1 << ": ";    
14         getline(cin, list[i]);       // 讀取一個字符串     
15     }
16 
17     cout << "Your list: \n";
18     display(list, SIZE);
19 
20     return 0;
21 }
22 
23 void display(const string list[], int n)
24 {
25     for (int i = 0; i < n; i++)
26         cout << list[i] << endl;
27 }

   該例程中,除了函數 getline() 外,程序像對待內置類型(int)一樣對待 string 對象

遞歸:

   函數調用自己成為遞歸;

   每個遞歸都創建自己的一套變量;

函數指針:

   可以編寫將另一個函數的地址作為參數的函數;

   這種方法與調用函數相比,允許在不同的時間傳遞不同的函數地址;

函數指針基礎知識:

   獲取函數地址;

   聲明函數的指針;

   使用函數指針來調用函數

   1. 獲取函數地址

    只要使用函數名即可,如果 think() 是一個函數,則 think 就是該函數的地址

    要區分函數的地址和函數的返回值:

      process ( think );  // 參數為函數地址,使得函數 process 能夠在函數內部調用 think() 函數

      thought ( think() ); // 參數為函數的返回值,先調用 think() 函數,其返回值傳給 thought

   2. 聲明函數指針

    聲明函數指針時,必須指定指針指向的函數類型:

      double pam ( int ); // 原型

      double ( *pf ) ( int ); // 指針類型聲明,將 pam 替換為了 (*pf),(*pf)是函數,pf 就是函數指針

      pf = pam;      // 將相應的函數地址賦給指針

    提示: 要聲明指向特定類型的函數指針,可以先編寫這種函數的原型,然後用(*pf)替換函數名

    註意: 函數地址賦給函數指針時,特征標和返回返回類型必須相同

   3. 使用指針來調用函數

    void estimate ( int lines,double (*pf) (int) );  // 函數原型

    estimate ( 50, pam);            // 讓 estime() 使用 pam() 函數

    (*pf) 扮演的角色與函數名相同,使用(*pf)時,只需要將它看成函數名

      double pam ( int );

      double (*pf) (int);

      pf = pam;       // 函數指針指向函數 pam()

      double x = pam (4);  // 使用函數名調用函數pam()

      double y = (*pf) (5);  // 使用函數指針調用函數pam()

      double y = pf(5);    // C++允許像使用函數名那樣使用 pf

復習題:

 函數 judge() 的返回值為 int,他將這樣一個函數地址作為參數:將 const char 指針作為參數,返回一個 int 值,編寫函數原型:

    int judge ( int (*pf) ( const char * ) )

  

    

      

 

 

  

          

     

  

    

 

  

     

C++ Primer Plus 筆記第七章