程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 【C++探索之旅】第一部分第七課:函數效應,分而治之

【C++探索之旅】第一部分第七課:函數效應,分而治之

編輯:關於C++

\

內容簡介

1、第一部分第七課函數效應,分而治之

2、第一部分第八課預告:傳值引用,文件源頭

 


函數效應,分而治之

上一課《【C++探索之旅】第一部分第六課:控制流程,隨心所至》中,我們學習了條件語句和循環語句。

這兩種語句也算是算法的核心了。在更早的課程中,我們學習了變量。這些都是所有編程語言的必備元素。

這一課我們又要學習一個幾乎所有編程語言都有的極重要元素:

函數

C++的所有程序都或多或少用到函數,到目前為止,你其實也已經用了好多次了,不過你可能只緣身在此山中,還雲深不知處。

函數的功用是:

將程序切分成更小的可重用的單元,有點像磚塊。一旦磚塊制作完畢,程序員所要做的就是用磚塊來造東西。

我們砌一堵牆,蓋一座小屋,或者摩天大樓,都需要不少磚塊。用函數構建我們的程序就似用磚塊搭建,而且如果拆除了,之後這些磚塊還可以重復使用。

慢慢你就能體會了。編程之美是需要時間去印證的,如果只遠觀而不"亵玩",沒有動手實驗,是不能進步的。

首先我們就挽起袖子,和好水泥,來學習如何制作"磚塊"(函數)吧。


函數的創建和使用

從這個課程的最初,我們已經使用了函數了。而且到目前為止都是那個函數:main函數(是我,是我,還是我...)。

這是C++程序的入口,程序是從main函數開始執行的。如下所示:

 

#include 
using namespace std;

int main() // main函數開始,程序的開始
{
 cout << "Hello World !" << endl;
 return 0;
} // main函數的結束,程序也隨之結束

 

以上的程序實際是從第四行開始,在第八行結束。也就是說,此程序的所有動作都是在一個函數裡完成的。我們並沒有跳轉到其他地方,沒有出這個main函數,而是按順序執行main函數中的各句指令。

 

既然我這樣說,聰明如你應該料想到了:我們可以寫其他的函數,把一個復雜的程序分割成相對獨立的區塊。

 

是的。但是為什麼要這麼做呢?

 

雖然說,把所有代碼都放在一個main函數裡是完全可以的,但這並不是一個好習慣。

 

假設我們要開發一個大型3D游戲。

 

大型3D游戲可是很復雜的,代碼數動辄上萬行。如果我們把這麼多代碼都一股腦兒放到main函數裡,那麼是很容易迷失在茫茫碼海中的。

 

比較理想的方式是在某個地方存放一小塊代碼,比如用於移動人物;另一個地方存放另一塊代碼,用於加載關卡,等等。

 

把代碼分成函數可以方便管理,使我們的代碼更容易被別人理解,我們自己回看時也不至於迷失了方向。

 

而且,假如你們是好幾個程序員一起協同開發,那麼函數可以讓你們更好地分配工作,比如某個人負責哪些功能開發,就需要寫哪些函數。

 

但這並不是函數的全部益處。

 

舉個例子:我們要計算平方根。上一課我們已經學習了怎麼做,我們使用了數學庫中的sqrt這個函數。

 

類似開平方根這樣常用的代碼塊,如果包裝成一個函數,那麼在不同地方使用時就不需要把相同的代碼重新拷貝一次了,只需要寫一下函數名就可以了。

 

所以函數使我們可以重復使用已有的代碼塊,極大地提高效率。

 

函數簡介

 

函數包含完成特定任務的一個代碼塊。它接收需要處理的數據,處理之,然後返回一個值。

 

可以把函數想象成一台制作香腸的機器,在輸入那一頭你把豬裝進去,輸出那一頭就出來香腸了。這酸爽。

 

\

 

輸入函數的數據稱為參數,而函數輸出的數據稱為返回值。如下圖所示:

 

\

 

你是否還記得我們上一課列出的多個數學函數中的pow函數,是用於計算次方值的。例如2的3次方,可以用pow(2, 3)來計算。

 

如果我們使用剛才所說的專業術語(參數,返回值),那麼pow函數的基本介紹可以如下所示:

 

接收兩個參數x和y

進行數學計算(x的y次方)

返回值就是計算結果

 

如下圖所示:

 

\

 

定義函數

 

好了,該放手一搏了。上面看了一些函數的例子,我們自己來定義一個函數吧。

 

首先,C++中所有的函數基本都遵循以下模板:

 

type functionName(arguments)
{
// Body : Instructions
}

 

上面的是英語的表述法,如果翻成中文就是:

 

類型 函數名(參數)

{

// 函數體:指令

}

 

關於這個模板我們需要掌握四點:

  1. 函數類型:對應輸出類型,也可以把其看做函數的類型。和變量類似,函數也有類型,這類型取決於函數返回值的類型。如果一個函數返回一個浮點數(帶小數點的),那麼自然我們會將函數類型定為float或者double;如果返回整數,那麼我們一般會將類型定為int或long。但是我們也可以創建不返回任何值的函數。

    函數名:這是你的函數的名字。我們已經見過不少函數名了,比如main,sqrt,pow。你可以給你的函數起任意名字,只要遵從給變量命名的相同的規則就好。

    函數的參數(對應輸入):參數位於函數名之後的圓括號內。這些參數是函數要用來做操作(運算)的數據。你可以給函數傳入任意數量的參數,也可以不傳入任何參數(例如main函數)。

    函數體:大括號規定了函數的起始和結束范圍。在大括號中你可以寫入任意多的指令。

     

    注意

    在C語言中,同一個程序裡不允許同名的函數。但是C++中允許有同名函數,稱為函數重載。只需要它們的參數不同(注意是參數不同,如果返回值不同而參數一樣不是函數重載,也不能通過編譯)。例如在C++中,int multiplication(int a, int b) 和 double multiplication(double c, double d) 就是不同的函數,盡管它們的函數名一樣,但是參數列表不一樣。但是如果定義兩個函數如下:int multiplication(int a, int b) 和 double multiplication(int c, int d),編譯是會出錯的,因為它們的參數一樣,只是返回值不一樣,是不能算不同函數的。

     

    我們自己來定義一個函數:

     

    int addTwo(int number)
    {
     int value(number + 2);
     // 在內存中申請一個int類型的"抽屜",起名叫value
     // 將參數中接收到的number進行加2操作
     // 將加法的結果存入value裡面
     
     return value;
     // 指定value為函數的返回值
    }

     

    注意:在參數的那個括號和函數體的大括號後面都沒有分號哦!

     

    分析此函數

     

    根據我們之前的解釋,你應該明白第一行是干什麼了吧。就是定義一個函數,名叫addTwo(英語"加2"的意思),接收一個int型參數作為輸入,操作結束之後會返回一個int型值。如下圖:

     

    \


    return value; 那一行是什麼意思呢?

     

    return是英語"返回"的意思,所以這一行指令的作用就是將value作為此函數的返回值返回。addTwo的參數number就類似之前那個圖中放入香腸制造機的豬,value就類似輸出的香腸。

     

    value的類型必須是int,因為在函數定義的第一行的返回值類型是int。

     

    函數調用

     

    我們的函數定義完畢,接下來該是使用它的時候了。函數的使用也有一個術語,叫做:函數調用。

    #include 
    using namespace std;
    
    int addTwo(int number)
    {
     int value(number + 2);
     return value;
    }
    
    int main()
    {
     int a(2), b(3);
     
     cout << "a的值是 " << a << endl;
     cout << "b的值是 " << b << endl;
     
     b = addTwo(a); // 函數調用
     
     cout << "a的值是 " << a << endl;
     cout << "b的值是 " << b << endl;
     
     return 0;
    }

     

    運行以上程序,顯示:

     

    a的值是 2

    b的值是 3

    a的值是 2

    b的值是 4

     

    在調用函數addTwo之後,a的值沒有改變;b的值改變了,等於a的值加上2。

     

    詳細解釋

     

    現在我們來看一個程序,包含一個multipleTwo函數,用於計算一個數的兩倍的值。

     

    我們暫時把multipleTwo函數寫在main函數之前,如果放在main函數之後會出錯,以後的課程我們會解釋為什麼。

    #include 
    using namespace std;
    
    int multipleTwo(int number)
    {
     return 2 * number;
    }
    
    int main()
    {
     int initial = 0, twice = 0;
     
     cout << "請輸入一個整數... ";
     cin >> initial;
     twice = multipleTwo(initial);
     cout << "這個數的兩倍是 " << twice << endl;
     
     return 0;
    }

    我們的程序是從main函數開始運行的,這個大家已經知道了。

     

    我們首先請求用戶輸入一個整數,將其值傳遞給multipleTwo函數,並且把multipleTwo函數的返回值賦給twice這個變量。

     

    仔細看下面這一行,這是我們最關心的一行代碼,因為正是這一行調用了我們的multipleTwo函數。

     

    twice = multipleTwo(initial);

     

    在括號裡,我們將變量initial當做輸入傳遞給函數,也正是這個變量,函數將其用於內部的處理。

     

    這個函數返回一個值,就是twice這個變量。

     

    其實這一行中,我們就是命令電腦:“讓multipleTwo函數給我計算initial的兩倍的值,並且將結果儲存到twice這個變量中”。

     

    詳細的分步解釋

     

    也許對於初學者,理解起來還是有些許困難。

     

    不用擔心,我相信通過下面的分步解釋,大家會明白得更透徹。

     

    這個特殊注釋的代碼向大家展示了程序的運行順序:

     

    #include 
    using namespace std;
    
    int multipleTwo(int number) // 6
    { 
        return 2 * number; // 7
    }
    
    int main() // 1
    { 
        int initial = 0, twice = 0; // 2 
        
        cout << "請輸入一個整數... "; // 3 
        
        cin >> initial; // 4 
        
        twice = multipleTwo(initial); // 5 
        
        cout << "這個數的兩倍是 " << twice << endl; // 8 
        
        return 0; // 9
    }

     

    上面的編號表示了執行的順序:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9

     

    1. 程序從main函數開始執行

      在main函數中的命令一行一行地被執行

      執行cout輸出

      執行cin讀入數據,賦值給變量initial

      讀入指令... 調用multipleTwo函數了,因此程序跳到上面的multipleTwo函數中去執行

      我們運行multipleTwo函數,並接受一個數作為輸入(number)

      我們對number做運算,並且結束multipleTwo函數,return意味著函數的結束,並且返回一個值。將返回值賦給twice變量。

      我們重新回到main函數的下一條指令,用cout輸出

      又一個return,這次是main函數的結束,於是整個程序運行完畢。

       

      變量initial被傳值給multipleTwo的參數number(另一個變量),稱為值傳遞。當然其實原理是做了一份變量initial的拷貝,把拷貝賦值給了number。

       

      這裡如果我們把initial改名為number也是可以的,並不會與函數multipleTwo的參數number沖突。因為參數number是屬於multipleTwo這個函數的專屬變量。

       

      多個參數

       

      上面的addTwo函數只有一個參數,我們也可以定義有多個參數的函數。其實之前見過的pow函數和getline函數就有兩個參數。

       

      int addition(int a, int b)
      {
       return a+b;
      }
      double multiplication(double a, double b, double c)
      {
       return a * b * c;
      }

       

      以上所定義的兩個函數中,我們合理地偷懶了:將參數運算的結果直接作為返回值,而沒有定義例如之前在addTwo函數中用到的value這樣的變量。這樣我們的代碼也達到了最簡化,我們是鼓勵這樣做的。程序員要會"偷懶"。

       

      上面的第一個函數addition(英語"加法,相加"的意思)接收兩個int型參數,返回它們的相加值。

       

      第二個函數multiplication(英語"乘法,相乘"的意思)接收三個double型參數,返回它們的相乘值。

       

      我們也可以定義參數類型不一樣的函數。例如:double different(int a, double b);

       

      無參數

       

      我們的函數也可以沒有參數。那麼在括號裡就不加任何東西。

       

      例如:

      string getName()
      { 
       cout << "請輸入你的名字 : ";
       string name;
       cin >> name;
       return name;
      }

       

      無返回值的函數

       

      函數也可以沒有返回值,那麼在定義的時候要將函數返回值類型設為void(英語"虛空,無"的意思)。不用加return語句了。例如:

      void sayHello()
      { 
          cout << "Hello!" << endl; 
          // 因為沒有返回值,也就沒有return語句了
      }
      int main()
      {
       sayHello();
       // 因為函數sayHello不返回任何值
       // 我們調用的時候也不會將其賦給某個變量了
       
       return 0;
      }

       


      實例

       

      下面我們會一起看幾個函數的實例,以便讀者對函數有更深入的了解。我們盡量展示不同情況,使大家看到可能出現的各種函數類型。

       

      歐元/人民幣轉換

       

      最近歐元兌換人民幣的匯率還是很穩定的在7左右徘徊,為什麼當年(2009)小編出來法國時,歐元的匯率那麼高(10),現在要換人民幣卻只有7。唉,就是辣麼不逢時。

       

      我們就來寫一個函數,用於轉換歐元到人民幣。

       

      查了一下最新的匯率:

      1歐元 = 7.0992 人民幣元

      #include 
      using namespace std;
      
      double conversion(double euros)
      {
      double rmb = 0;
      rmb = 7.0992 * euros;
      return rmb;
      }
      
      int main()
      {
      cout << "10 歐元 = " << conversion(10) << "人民幣" << endl;
       cout << "50 歐元 = " << conversion(50) << "人民幣" << endl;
       cout << "100 歐元 = " << conversion(100) << "人民幣" << endl;
       cout << "200 歐元 = " << conversion(200) << "人民幣" << endl;
      return 0;
      }

      你也可以寫一個人民幣轉換為歐元的小程序。

       

      懲罰

       

      接下來看一個函數,這個函數不會返回任何值,所以類型是void。這個函數會根據傳入的參數在屏幕上顯示一定次數的信息。這個函數只有一個參數,那就是顯示懲罰語句的次數:

      #include 
      using namespace std;
      
      void punish(int lineNumber)
      {
      int i;
      for (i = 0 ; i < lineNumber ; i++)
      {
        cout << "我不應該有錢任性" << endl;
      }  
      }
      
      int main(int argc, char *argv[])
      {  
      punish(5);
      return 0;
      }

       

      顯示結果如下:

       

      我不應該有錢任性

      我不應該有錢任性

      我不應該有錢任性

      我不應該有錢任性

      我不應該有錢任性

       

      矩形面積

       

      矩形的面積很容易計算:長 x 寬。長度乘以寬度。

       

      我們來寫一個求矩形面積的函數,它有兩個參數:矩形的長和矩形的寬。返回值是矩形的面積:

       

      #include 
      using namespace std;
      
      double rectangleArea(double length, double width)
      {
          return length * width;
      }
      
      int main()
      {
          cout << "長是10,寬是5的矩形面積是 " << rectangleArea(10, 5) << endl;
          cout << "長是3.5,寬是2.5的矩形面積是 " << rectangleArea(3.5, 2.5) << endl;
          cout << "長是9.7,寬是4.2的矩形面積是 " << rectangleArea(9.7, 4.2) << endl;
          
          return 0;
      }

       

      顯示結果:

       

      長是10,寬是5的矩形面積是 50.000000

      長是3.5,寬是2.5的矩形面積是 8.750000

      長是9.7,寬是4.2的矩形面積是 40.740000

       

      我們可以直接在函數裡顯示 長,寬和計算所得的面積嗎?

       

      當然可以。這樣的情況下,函數就不必返回任何值了,函數計算出矩形面積,然後直接顯示在屏幕上:

      #include 
      using namespace std;
      
      void rectangleArea(double length, double width)
      {
       double area = 0;
       area = length * width;
       cout << "長為 "<< length << " 寬為 " << width << " 的矩形的面積是 " << area << endl;
      }
      
      int main()
      {
       rectangleArea(10, 5);
       rectangleArea(3.5, 2.5);
       rectangleArea(9.7, 4.2);
       
       return 0;
      }

       

      我們可以看到,cout在函數體內被調用,顯示的結果和之前把cout放在main函數裡是一樣的。只不過我們用的方法不一樣罷了。

       

      菜單

       

      我們來寫一個餐館菜單的例子。

       

      #include 
      using namespace std;
      
      int menu()
      {
       int choice = 0;
       
       while (choice < 1 || choice > 4)
       {
       cout << "菜單 :" <> choice;
       }
       
       return choice;
      }
      
      int main()
      {
       switch (menu())
       {
       case 1:
       cout << "您點了北京烤鴨" << endl;
       break;
       case 2:
       cout << "您點了麻婆豆腐" << endl;
       break;
       case 3:
       cout << "您點了魚香肉絲" << endl;
       break;
       case 4:
       cout << "您點了剁椒魚頭" << endl;
       break;
       }
       
       return 0;
      }

       

      這個程序還可以改進:你可以在用戶輸入一個錯誤的數字時顯示一個錯誤信息,而不是直接繼續讓其點單。

       


      總結

      1. 函數包含具有特定目的的一段代碼。

        每個C++程序至少有一個函數:main函數。這是程序的入口。

        把程序切分為有特定作用的各個函數是管理代碼的好方式。

        程序中,我們可以多次調用同一個函數。

        一個函數可以接收數據(通過參數),也可以返回數據(通過return)。


        第一部分第八課預告

        今天的課就到這裡,一起加油吧!

        下一課我們學習:傳值引用,文件源頭

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