函數的定義與使用
函數定義
類型標識符 函數名稱(形式參數表) { 語句序列 }
<type1> name1 <type2> name2 ... <typen> namen
- 這些是被初始化的內部變數,其生命週期和可見性僅限於函數內部
- 表示返回值類型,由
return
語句給出返回值 - 若無返回值,寫
void
,不必寫return
語句。
函數的呼叫
呼叫前先宣告函數:
- 若函數定義在呼叫點之前,可以不另外宣告;
- 若函數定義在呼叫點之後,必須要在呼叫函數前宣告函數原型:
類型標識符 被呼叫函數名稱(含類型說明的形參表);
- 呼叫形式
- 函數名稱(實參列表)
- 巢狀呼叫
- 在一個函數的函數體中,呼叫另一個函數。
- 遞迴呼叫
- 函數直接或間接呼叫自身。
例3-1:編寫一個求x的n次方的函數
#include <iostream> using namespace std; // 計算x的n次方 double power(double x, int n) { double val = 1.0; while (n--) val *= x; return val; } int main() { cout << "5 to the power 2 is " << power(5, 2) << endl; return 0; }
例3-2:數制轉換
題目:輸入一個8位二進位數,將其轉換為十進位數輸出。
例如:1101₂ = 1(2³) + 1(2²) + 0(2¹) + 1(2⁰) = 13₁₀
所以,如果輸入 1101
,則應輸出 13
。
#include <iostream> using namespace std; double power(double x, int n); // 計算x的n次方 int main() { int value = 0; cout << "請輸入一個8位二進位數字: "; for (int i = 7; i >= 0; i--) { char ch; cin >> ch; if (ch == '1') value += static_cast<int>(power(2, i)); } cout << "十進位值為 " << value << endl; return 0; } double power(double x, int n) { double val = 1.0; while (n--) val *= x; return val; }
例3-3:編寫程式求 π 的值
π 的計算公式如下:
其中 arctan
用如下形式的級數計算:
直到級數某項絕對值不大於 10⁻¹⁵
為止;π 和 x 均為 double
型。
#include <iostream> using namespace std; double arctan(double x) { double sqr = x * x; double e = x; double r = 0; int i = 1; while (e / i > 1e-15) { double f = e / i; r = (i % 4 == 1) ? r + f : r - f; e = e * sqr; i += 2; } return r; } int main() { double a = 16.0 * arctan(1/5.0); double b = 4.0 * arctan(1/239.0); cout << "π = " << a - b << endl; return 0; }
例3-4:尋找並輸出11~999之間的數m,它滿足m、m²和m³均為回文數。
分析:用除以10取餘的方法,從最低位開始,依次取出該數的各位數字。按反序重新構成新的數,與原數比較是否相等,若相等,則原數為回文數。
#include <iostream> using namespace std; bool symm(unsigned n) { unsigned i = n; unsigned m = 0; while (i > 0) { m = m * 10 + i % 10; i /= 10; } return m == n; } int main() { for(unsigned m = 11; m < 1000; m++) if (symm(m) && symm(m * m) && symm(m * m * m)) { cout << "m = " << m; cout << " m * m = " << m * m; cout << " m * m * m = " << m * m * m << endl; } return 0; }
例3-5:計算如下公式,並輸出結果:
其中 r、s 的值由鍵盤輸入。sin x 的近似值按如下公式計算,計算精度為 10⁻¹⁰
。
#include <iostream> #include <cmath> using namespace std; const double TINY_VALUE = 1e-10; double tsin(double x) { double g = 0; double t = x; int n = 1; do { g += t; n++; t = -t * x * x / (2 * n - 1) / (2 * n - 2); } while (fabs(t) >= TINY_VALUE); return g; } int main() { double k, r, s; cout << "r = "; cin >> r; cout << "s = "; cin >> s; if (r * r <= s * s) k = sqrt(tsin(r)*tsin(r) + tsin(s)*tsin(s)); else k = tsin(r * s) / 2; cout << k << endl; return 0; }
例3-6:擲骰子的隨機遊戲
每個骰子有六面,點數分別為1、2、3、4、5、6。遊戲者在程式開始時輸入一個無符號整數,作為產生隨機數的種子。
每輪擲兩次骰子,第一輪如果和數為7或11則為勝,遊戲結束;和數為2、3或12則為負,遊戲結束;和數為其他值則將此值作為自己的點數,繼續第二輪、第三輪…直到某輪的和數等於點數則取勝,若在此前出現和數為7則為負。
由 rollDice
函數負責模擬擲骰子、計算和數並輸出和數。
#include <iostream> #include <cstdlib> using namespace std; enum GameStatus { WIN, LOSE, PLAYING }; int main() { int sum, myPoint; GameStatus status; unsigned seed; int rollDice(); cout << "請輸入一個無符號整數: "; 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 << "點數為 " << myPoint << endl; break; } while (status == PLAYING) { // 只要狀態為PLAYING,繼續 sum = rollDice(); if (sum == myPoint) // 某輪的和數等於點數則取勝 status = WIN; else if (sum == 7) // 出現和數為7則為負 status = LOSE; } if (status == WIN) cout << "玩家勝利" << endl; else cout << "玩家失敗" << endl; return 0; } int rollDice() { int die1 = 1 + rand() % 6; int die2 = 1 + rand() % 6; int sum = die1 + die2; cout << "玩家擲出 " << die1 << " + " << die2 << " = " << sum << endl; return sum; }
例3-7:輸入兩個整數,求平方和
#include <iostream> using namespace std; int fun2(int m) { return m * m; } int fun1(int x, int y) { return fun2(x) + fun2(y); } int main() { int a, b; cout << "請輸入兩個整數 (a 和 b): "; cin >> a >> b; cout << "a 和 b 的平方和: " << fun1(a, b) << endl; return 0; }
例3-8:求 n!
分析:計算 n! 的公式如下:
這是一個遞迴形式的公式,應該用遞迴函數實現。
#include <iostream> using namespace std; unsigned fac(int n) { unsigned f; if (n == 0) f = 1; else f = fac(n - 1) * n; return f; } int main() { unsigned n; cout << "請輸入一個正整數: "; cin >> n; unsigned y = fac(n); cout << n << "! = " << y << endl; return 0; }
例3-9:用遞迴法計算從 n 個人中選擇 k 個人組成一個委員會的不同組合數。
分析:
由 n 個人裡選 k 個人的組合數 = 由 n-1 個人裡選 k 個人的組合數 + 由 n-1 個人裡選 k-1 個人的組合數。
當 n = k 或 k = 0 時,組合數為 1。
#include <iostream> using namespace std; 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); } int main() { int n, k; cout << "請輸入兩個整數 n 和 k: "; cin >> n >> k; cout << "C(n, k) = " << comm(n, k) << endl; return 0; }
例3-10:有三根針 A、B、C。A 針上有 N 個盤子,大的在下,小的在上,要求把這 N 個盤子從 A 針移到 C 針,在移動過程中可以借助 B 針,每次只允許移動一個盤,且在移動過程中在三根針上都保持大盤在下,小盤在上。
將 n 個盤子從 A 針移到 C 針可以分解為三個步驟:
- 將 A 上 n-1 個盤子移到 B 針上(借助 C 針);
- 把 A 針上剩下的一個盤子移到 C 針上;
- 將 n-1 個盤子從 B 針移到 C 針上(借助 A 針);
上面三個步驟包含兩種操作:
- 將多個盤子從一個針移到另一個針上,這是一個遞迴的過程。由
hanoi
函數實現。 - 將1個盤子從一個針上移到另一針上。用
move
函數實現。
#include <iostream> using namespace std; // 將 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 << "請輸入盤子的數量: "; cin >> m; cout << m << " 個盤子的移動步驟如下:" << endl; hanoi(m, 'A', 'B', 'C'); return 0; }
函數的參數傳遞
- 在函數被呼叫時才分配形參的存儲單元
- 實參可以是常量、變數或表達式
- 實參類型必須與形參相符或可隱式轉換為形參類型
- 值傳遞是傳遞參數值,即單向傳遞
- 引用傳遞可以實現雙向傳遞
- 常引用作參數可以保障實參資料的安全
例3-11:輸入兩個整數並交換(值傳遞)
#include<iostream> using namespace std; void swap(int a, int b) { int t = a; a = b; b = t; } int main() { int x = 5, y = 10; cout << "x = " << x << " y = " << y << endl; swap(x, y); cout << "x = " << x << " y = " << y << endl; return 0; }
例3-12:輸入兩個整數交換後輸出(引用傳遞)
#include<iostream> using namespace std; void swap(int& a, int& b) { int t = a; a = b; b = t; } int main() { int x = 5, y = 10; cout << "x = " << x << " y = " << y << endl; swap(x, y); cout << "x = " << x << " y = " << y << endl; return 0; }
引用類型
引用 &
是標識符的別名。例如:
int i, j; int &ri = i; // 定義int引用ri,並初始化為變數i的引用 j = 10; ri = j; // 相當於 i = j;
可變數量形參
使用模板類 initializer_list<T>
(T 為類模板,模板將於第9章介紹)可向函數傳遞同類型不定個數參數,例如:
void log_info(initializer_list<string> lst) { for (auto &info: lst) cout << info << ' '; cout << endl; } log_info({"Hello", "world", "!"});
initializer_list<string> lst
接受不定個數字串實參
注意,實參以大括號列表方式給出
使用範圍 for
語句遍歷 lst
,auto
自動推斷元素為 string
類型