【C++複習總結回顧】—— 【二】函數


一、函數定義和調用

在這裏插入圖片描述

二、函數的遞歸調用

從經典的 漢諾塔Hanoi 問題入手
在這裏插入圖片描述
思路如下:

void hanoi(int n, char A, char B, char C)
{
    if (n == 1)
        move(A, C);
    else
    {
        hanoi(n - 1, A, C, B); //將上面的n-1個藉助C從A移動到B
        move(A, C); //將最下面一個從A移到C
        hanoi(n - 1, B, A, C); //將n-1個從B藉助A移動到C
    }
}

具體代碼:

//將src針的最上面一個盤子移動到dest針上
void move(char src, char dest) { 
    cout << src << " --> " << dest << endl; } 

//將n個盤子從src針移動到dest針,以medium針作爲中轉
void hanoi(int n, char src, char medium, char dest)
{
    if (n == 1)
        move(src, dest);
    else
    {
        hanoi(n - 1, src, dest, medium);
        move(src, dest);
        hanoi(n - 1, medium, src, dest);
    }
}

int main()
{
    int m;
    cout << "Enter the number of diskes: ";
    cin >> m;
    cout << "the steps to moving " << m << " diskes:" << endl;
    hanoi(m, 'A', 'B', 'C');
    return 0;
}

在這裏插入圖片描述

當函數發生遞歸調用時,同一個局部變量在不同遞歸深度上可以同時存在不同的取值,這在底層是如何做到的?

答:對同一個函數的多次不同調用中,編譯器會爲函數的形參和局部變量分配不同的空間,他們互不影響。

三、函數的參數傳遞

在這裏插入圖片描述

1. 值傳遞

傳遞參數值,單向傳遞

2. 引用傳遞(需要修改形參值的時候使用)

我們常用的交換函數就需要用到引用傳遞,實現雙向傳遞,修改傳進來的形參值

void swap(int &a, int &b){
 int temp = a;
 a = b;
 b = temp;

學習 引用傳遞 需詳細掌握以下 引用 的知識

變量的引用

int &r = n;
某個變量的引用,等價於這個變量(即同一個人,不管誰發生改變,另一個也會隨之改變)
int n = 7;
int &r = n; //定義引用時一定要將其初始化引用某個*變量*
r = 4;
cout<<r; //4
cout<<n; //4
n = 5;
cout<<r; //5
int a = 4;
int b = 5;
int &r1 = a;
int &r2 = r1; //等價於 int &r2 = a; r2也引用a
r2 = 10;
cout<<a; //10

一旦一個引用被初始化後,就不能改爲指向其他對象

int a = 4;
int b = 5;
int &r1 = a;
//*一個引用是從一而終的*,該語句並不表示r1引用了b,而是b的值賦給了r1
r1 = b; 
cout<<a; //5

引用作爲函數的返回值

int n = 4;
int &setValue(){ //返回了n的引用
    return n;
}
int main(){
    setValue() = 40; //函數返回的是n的引用,所以可以作爲左值被賦值
    cout<<n; //給n的引用賦值40 等價於 給n賦值40
}

常引用
const int &r = n;
不能通過常引用去修改其引用的內容

int n = 100;
const int &r = n;
r = 50; //wrong
n = 49; //right n的引用r的值也隨之改變

三、內聯函數

在這裏插入圖片描述
內聯函數的調用過程:

inline int Max(int a, int b){
    if(a>b)
        return a;
    return b;
}

假如主函數中有如下語句

K = Max(n1,n2);

等價於

if(n1 > n2)
    tmp = n1;
else 
    tmp = n2;
K = tmp;

即直接把函數體嵌入到代碼中,而沒有函數調用的出入棧的過程。

編譯器並不承諾將inline修飾的函數作爲內聯,而在現代編譯器中,沒有inline修飾的函數也可能被編譯爲內聯

四、帶默認形參值的函數(缺省函數)

在這裏插入圖片描述
在相同的作用域內,不允許在同一個函數的多個聲明中對同一個參數的默認值重複定義,即使前後定義的值相同也不行。

五、函數重載(形參個數/類型不同)

在這裏插入圖片描述

函數重載提高了程序的可擴充性。
(C語言中不允許同名函數,即沒有重載的概念)

注:編譯器不以形參名和返回值來區分重載。 若只有返回值類型不同,則不叫重載,叫重複定義

double func(int a, string var){ };
int func(int x, string b){ };

六、典型例題

1. 數制轉換

在這裏插入圖片描述

double power(double x, int n); //x的n次方
int main(){
    int value = 0;
    cout<<"please enter 8 bit binary number:";
    for(int i = 7; i>=0; i--){ //從高位往低位讀入二進制數
        char ch;
        cin>>ch; //以字符形式讀取
        if(ch == '1')
        	//強轉
            value += static_cast<int>(power(2,i)); //value += (int)(power(2,i));
    }
    cout<<"decimal value is "<<value<<endl;
    return 0;
}
double power(double x, int n){
    double sum = 1.0;
    while(n--)
        sum = sum*x;
    return sum;
}

或者用數學方式處理

//以int形式讀入的數學方式處理
   while ( binary != 0 )
   {
      decimal += binary % 10 * bit;
      binary /= 10;
      bit *= 2;
   }

2. 編寫程序求 π 的值

在這裏插入圖片描述

double arctanx(double x)
{
    double sqr = x * x; //x每次都乘以x2
    double e = x; //保存x的次方,分子
    double sum = 0; //保存最終結果
    int i = 1; //分母
    int flag = 1;
    while (e / i > 1e-15)
    {
        double f = flag * e / i;
        sum += f;
        e = e * sqr;
        i += 2;
        flag = -flag;
    }
    return sum;
}
int main()
{
	 //注意:因爲整數相除結果取整,如果參數寫1/5,1/239,結果就都是0
    double a = 16.0 * arctanx(1 / 5.0);
    double b = 4.0 * arctanx(1 / 239.0);
    cout << "PI = " << a - b << endl;
    return 0;
}

3. 擲骰子

  • 每個骰子有六面,點數分別爲1、2、3、4、5、6。遊戲者在程序開始時輸入一個無 符號整數,作爲產生隨機數的種子。
  • 每輪投兩次骰子,第一輪如果和數爲7或11則爲勝,遊戲結束;和數爲2、3或12 則爲負,遊戲結束;和數爲其它值則將此值作爲自己的點數,繼續第二輪、第三輪…直到 某輪的和數等於點數則取勝,若在此前出現和數爲7則爲負。

此處需要用到 rand 函數,rand產生的是僞隨機數,即每次運行產生的是同一串隨機數序列
在這裏插入圖片描述

//投骰子、計算和數、輸出和數
int rollDice()
{
    int die1 = 1 + rand() % 6;
    int die2 = 1 + rand() % 6;
    int sum = die1 + die2;
    cout << "player rolled " << die1 << " + " << die2 << " = " << sum << endl;
    return sum;
}

enum GameStatus
{
    WIN,
    LOSE,
    PLAYING
};

int main()
{
    int sum, myPoint;
    GameStatus status;
    unsigned seed;
    cout << "Please enter an unsigned integer: ";
    cin >> seed;      //輸入隨機數種子
    srand(seed);      //將種子傳遞給rand()
    sum = rollDice(); //第一輪投骰子、計算和數
    switch (sum)
    {
    case 7: //如果和數爲7或11則爲勝,狀態爲WIN
    case 11:
        status = WIN;
        break;
    case 2: //和數爲2、3或12則爲負,狀態爲LOSE
    case 3:
    case 12:
        status = LOSE;
        break;
    default: //其它情況,尚無結果,狀態爲 PLAYING,記下點數
        status = PLAYING;
        myPoint = sum;
        cout << "point is " << myPoint << endl;
        break;
    }
    while (status == PLAYING)
    { //只要狀態爲PLAYING,繼續
        sum = rollDice();
        if (sum == myPoint) //某輪的和數等於點數則取勝
            status = WIN;
        else if (sum == 7) //出現和數爲7則爲負
            status = LOSE;
    }
    //當狀態不爲PLAYING時循環結束,輸出遊戲結果
    if (status == WIN)
        cout << "player wins" << endl;
    else
        cout << "player loses" << endl;
    return 0;
}

在這裏插入圖片描述

4. 遞歸計算從n個人中選k個人不同組合數。

在這裏插入圖片描述

int comm(int n, int k)
{
    if (k > n)
        return 0;
    else if (n == k || k == 0)
        return 1;
    else
        return comm(n - 1, k) + comm(n - 1, k - 1);
}

5. 遞歸實現 getPower 計算 x的y次方

此處需要考慮兩種情況,x是整數 和 x是小數 ,利用重載編寫兩個做同樣運算的函數 getPower

在這裏插入圖片描述



👉 👉 👉 原文首發 - 小牛肉的個人博客,歡迎來訪~👈 👈 👈

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章