# 前言

為什麼選擇 C++ ,為什麼不選擇更常見的 Python ,在現代大語言模型讓程式碼產出的成本大幅度降低,我認為應該著重放在理解相關邏輯,應該在第一次學習的時候,盡量了解底層程式碼的思考邏輯,讓之後再學習相關的內容,有個好的基礎,當然並不是越底層越好,也不過度重複造輪子,我認為 C++ 是個很好的甜蜜點,在學習物件導向還有資料型態相關的邏輯,還有在 APCS 考試中與相關的演算法比賽 C++ 都是一定支援的,也有龐大的社群方便學習。

# C++ 語法

讓我們拆解以下程式碼,來更深入了解它:

範例

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!";
  return 0;
}

# 範例解說

第 1 行: #include <iostream> 是一個標頭檔(header file)函式庫,讓我們可以使用輸入輸出物件,例如第 5 行使用的 cout 。標頭檔為 C++ 程式增加了功能。

第 2 行: using namespace std 代表我們可以直接使用標準函式庫(standard library)中物件與變數的名稱。

如果你還不太理解 #include <iostream> 和 using namespace std 是如何運作的,先不用擔心。只要把它們當作幾乎每個程式都會出現的固定寫法即可。

第 3 行:空白行。C++ 會忽略空白,但我們利用空白行讓程式碼更容易閱讀。

第 4 行:另一個幾乎每個 C++ 程式都會出現的東西是 int main() ,這稱為函式(function)。任何寫在其大括號 {} 內的程式碼都會被執行。

第 5 行: cout (唸作 "see-out")是一個物件,搭配插入運算子(insertion operator) << 來輸出/印出文字。在這個範例中,它會輸出 "Hello World!"。

注意:C++ 是區分大小寫的,"cout" 和 "Cout" 代表不同的意思。

注意:每一行 C++ 陳述式(statement)都必須以分號 ; 結尾。

注意: int main() 的內容也可以寫成這樣:

int main () { cout << "Hello World! "; return 0; }

記住:編譯器會忽略空白字元。不過,將程式碼分成多行會讓它更容易閱讀。

第 6 行: return 0; 結束 main 函式。

第 7 行:別忘了加上結尾的大括號 } ,才能真正結束 main 函式。

# 省略命名空間(Omitting Namespace)

你可能會看到一些 C++ 程式在沒有 using namespace std; 這一行的情況下也能執行。 using namespace std; 這個陳述式是可以省略的,並且可以用 std 關鍵字加上 :: 運算子來取代,適用於部分物件(例如下方範例中的 std::cout ):

範例

#include <iostream>
int main() {
  std::cout << "Hello World!";
  return 0;
}

這兩種寫法在 C++ 中都是合法的。使用 std:: 可以清楚表明名稱的來源,並避免在較大型的程式中發生命名衝突。

# 我們會使用哪一種?

在這個教學中,我們大多會使用 using namespace std;

這樣可以讓程式碼更簡短、更容易閱讀,同時在學習 C++ 基礎時,能幫助初學者專注於理解語言本身,而不用在每個範例中反覆寫 std:: 。

當你開始撰寫更大型或更進階的程式時,可能會更偏好明確使用 std:: 。在實際的 C++ 程式碼中,你會看到這兩種寫法並存。

# C++ 陳述式(Statements)

電腦程式(computer program) 是一連串要讓電腦「執行(executed)」的「指令(instructions)」。

在程式語言中,這些程式指令被稱為 陳述式(statements)。

以下這行陳述式「指示」編譯器將文字 "Hello World" 印到螢幕上:

cout << "Hello World!";

務必記得以分號 ; 結束陳述式。

如果忘記加分號 ; ,就會發生錯誤,程式將無法執行:

cout << "Hello World!"

# 多個陳述式

大多數 C++ 程式都包含許多陳述式。

這些陳述式會依照撰寫的順序,一個接一個地被執行:

cout << "Hello World!";
cout << "Have a good day!";
return 0;

上面範例中共有三個陳述式:

  1. cout << "Hello World!";
  2. cout << "Have a good day!";
  3. return 0;

第一個陳述式最先被執行(印出 "Hello World!");接著執行第二個陳述式(印出 "Have a good day!");最後執行第三個陳述式(成功結束 C++ 程式)。

只要記得永遠以分號結尾以避免錯誤即可。

# C++ 輸出(Output)

cout 物件搭配 << 運算子,用來輸出數值與印出文字。

記得將文字用雙引號( "" )包起來:

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!";
  return 0;
}

你可以加入任意數量的 cout 物件。不過要注意,它並不會在輸出的結尾自動插入換行:

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!";
  cout << "I am learning C++";
  return 0;
}

# 印出數字

cout 也可以用來印出數字。

不過和文字不同,數字不需要放在雙引號裡:

#include <iostream>
using namespace std;
int main() {
  cout << 3;
  return 0;
}

也可以直接進行數學運算:

cout << 3 + 3;
cout << 2 * 5;

# 換行(New Lines)

要在輸出中插入換行,可以使用 \n 字元:

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!\n";
  cout << "I am learning C++";
  return 0;
}

也可以另外使用一個 << 運算子,把 \n 字元放在文字後面:

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!" << "\n";
  cout << "I am learning C++";
  return 0;
}

小提示: 連續兩個 \n 字元會產生一個空白行:

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!" << "\n\n";
  cout << "I am learning C++";
  return 0;
}

另一種插入換行的方式,是使用 endl 這個操縱器(manipulator):

#include <iostream>
using namespace std;
int main() {
  cout << "Hello World!" << endl;
  cout << "I am learning C++";
  return 0;
}

\n 和 endl 都可以用來換行,不過 \n 較常被使用。

# \n 到底是什麼?

換行字元( \n )被稱為 跳脫序列(escape sequence),它會強制游標移動到螢幕上下一行的開頭,因此產生換行的效果。

其他常見的合法跳脫序列範例:

跳脫序列 說明
\t 建立一個水平定位(tab)
\\ 插入反斜線字元(\)
\" 插入雙引號字元

# C++ 註解(Comments)

註解可以用來解釋 C++ 程式碼,讓程式更容易閱讀,也可以用來在測試替代程式碼時暫時停用某段程式。註解可以是單行或多行。

# 單行註解

單行註解以兩個斜線( // )開頭。

// 到該行結尾之間的任何文字都會被編譯器忽略(不會被執行)。

這個範例在一行程式碼前使用單行註解:

// This is a comment
cout << "Hello World!";

這個範例在一行程式碼的結尾使用單行註解:

cout << "Hello World!"; // This is a comment

# C++ 多行註解

多行註解以 /* 開頭,並以 */ 結尾。

/* 和 */ 之間的任何文字都會被編譯器忽略:

/* The code below will print the words Hello World!
to the screen, and it is amazing */
cout << "Hello World!";

# 該用單行還是多行註解?

這取決於你自己的選擇。一般來說,短註解會使用 // ,較長的說明則使用 /* */ 。

# C++ 變數(Variables)

變數是用來儲存資料值的容器。

C++ 中有多種不同 ** 型態(types)** 的變數(以不同關鍵字定義),例如:

  • int - 儲存整數(不含小數),例如 123 或 -123
  • double - 儲存浮點數(含小數),例如 19.99 或 -19.99
  • char - 儲存單一字元,例如 'a' 或 'B'。char 的值須用單引號包起來
  • string - 儲存文字,例如 "Hello World"。string 的值須用雙引號包起來
  • bool - 儲存兩種狀態的值:true 或 false

# 宣告(建立)變數

要建立變數,需指定型態並賦予它一個值:

語法:

type variableName = value;

其中 type 是 C++ 型態之一(例如 int ), variableName 是變數的名稱(例如 x 或 myName)。等號用來將值賦予變數。

建立一個用來儲存數字的變數:

int myNum = 15;
cout << myNum;

也可以先宣告變數而不賦值,稍後再賦值:

int myNum;
myNum = 15;
cout << myNum;

# 改變變數的值

注意,如果對已存在的變數賦予新的值,會覆蓋掉先前的值:

int myNum = 15; // myNum is 15
myNum = 10; // Now myNum is 10
cout << myNum; // Outputs 10

# 其他型態

展示其他資料型態:

int myNum = 5; // Integer (whole number without decimals)
double myFloatNum = 5.99; // Floating point number (with decimals)
char myLetter = 'D'; // Character
string myText = "Hello"; // String (text)
bool myBoolean = true; // Boolean (true or false)

# 顯示變數

cout 物件搭配 << 運算子用來顯示變數。

要同時結合文字與變數,用 << 運算子分隔它們:

int myAge = 35;
cout << "I am " << myAge << " years old.";

也可以結合不同型態:

string name = "John";
int age = 35;
double height = 6.1;
cout << name << " is " << age << " years old and " << height << " feet tall.";

# 將變數相加

要把一個變數加到另一個變數,可以使用 + 運算子:

int x = 5;
int y = 6;
int sum = x + y;
cout << sum;

# 宣告多個變數

要宣告多個相同型態的變數,可以用逗號分隔的清單:

int x = 5, y = 6, z = 50;
cout << x + y + z;

也可以在同一行中,把相同的值賦予多個變數:

int x, y, z;
x = y = z = 50;
cout << x + y + z;

# 識別字(Identifiers)

所有 C++ 變數都必須以唯一的名稱來識別。

這些唯一的名稱稱為識別字(identifiers)。

識別字可以是簡短的名稱(如 x 和 y),也可以是更具描述性的名稱(如 age、sum、totalVolume)。

注意: 建議使用具描述性的名稱,以建立容易理解與維護的程式碼:

// Good
int minutesPerHour = 60;
// OK, but not so easy to understand what m actually is
int m = 60;

變數命名的一般規則:

  • 名稱可以包含字母、數字與底線
  • 名稱必須以字母或底線(_)開頭
  • 名稱區分大小寫( myVar 與 myvar 是不同的變數)
  • 名稱不能包含空白或特殊字元,如!、#、% 等
  • 保留字(如 C++ 關鍵字 int )不能作為名稱使用

# 常數(Constants)

當你不希望其他人(或自己)更動已存在的變數值時,可以使用 const 關鍵字(這會將變數宣告為「常數」,代表不可變更且唯讀):

const int myNum = 15; // myNum will always be 15
myNum = 10; // error: assignment of read-only variable 'myNum'

當你有不太可能改變的值時,應該一律將該變數宣告為常數:

const int minutesPerHour = 60;

# 關於常數的注意事項

宣告常數變數時,必須同時賦予一個值:

const int minutesPerHour = 60;

但以下寫法是行不通的:

const int minutesPerHour;
minutesPerHour = 60; // error

# 實際案例

我們通常會把變數名稱簡化,以對應其資料型態(例如 int 型態用 myInt 或 myNum,char 型態用 myChar),這是為了避免混淆。

以下是一個實際使用變數的範例,程式儲存一位大學生的不同資料:

// Student data
int studentID = 15;
int studentAge = 23;
double studentFee = 75.25;
char studentGrade = 'B';
// Print variables
cout << "Student ID: " << studentID << "\n";
cout << "Student Age: " << studentAge << "\n";
cout << "Student Fee: " << studentFee << "\n";
cout << "Student Grade: " << studentGrade << "\n";

計算矩形面積的範例(將長與寬相乘):

// Create integer variables
int length = 4;
int width = 6;
// Calculate the area of a rectangle
int area = length * width;
// Print the variables
cout << "Length is: " << length << "\n";
cout << "Width is: " << width << "\n";
cout << "Area of the rectangle is: " << area << "\n";

# C++ 使用者輸入(User Input)

前面已經學過 cout 用來輸出(印出)數值。現在我們要使用 cin 來取得使用者輸入。

cin 是一個預先定義好的變數,會透過擷取運算子( >> )從鍵盤讀取資料。

以下範例中,使用者可以輸入一個數字,並儲存到變數 x ,接著印出 x 的值:

int x;
cout << "Type a number: "; // Type a number and press enter
cin >> x; // Get user input from the keyboard
cout << "Your number is: " << x; // Display the input value

# 補充知識

cout 唸作 "see-out",用於輸出,使用插入運算子( << )

cin 唸作 "see-in",用於輸入,使用擷取運算子( >> )

# 建立一個簡易計算機

這個範例中,使用者需要輸入兩個數字,接著我們計算(相加)這兩個數字並印出總和:

int x, y;
int sum;
cout << "Type a number: ";
cin >> x;
cout << "Type another number: ";
cin >> y;
sum = x + y;
cout << "Sum is: " << sum;

這樣你就完成了一個基本的計算機!

小提示: cin 與 cout 都屬於 <iostream> 函式庫,這是 standard input/output streams(標準輸入/輸出串流)的縮寫。

# C++ 資料型態(Data Types)

如同前面「變數」章節所提到的,C++ 中的變數必須指定資料型態:

int myNum = 5; // Integer (whole number)
float myFloatNum = 5.99; // Floating point number
double myDoubleNum = 9.98; // Floating point number
char myLetter = 'D'; // Character
bool myBoolean = true; // Boolean
string myText = "Hello"; // String

# 基本資料型態

資料型態指定了變數要儲存的資訊的大小與種類:

資料型態 大小 說明
bool 1 byte 儲存 true 或 false 值
char 1 byte 儲存單一字元/字母/數字,或 ASCII 值
int 2 或 4 bytes 儲存整數,不含小數
float 4 bytes 儲存含小數的浮點數,精度約可儲存 6-7 位小數
double 8 bytes 儲存含小數的浮點數,精度約可儲存 15 位小數

# 數值型態(Numeric Types)

當你需要儲存不含小數的整數(例如 35 或 1000)時使用 int ;當你需要儲存含小數的浮點數(例如 9.99 或 3.14515)時,使用 float 或 double 。

int myNum = 1000;
cout << myNum;
float myNum = 5.75;
cout << myNum;
double myNum = 19.99;
cout << myNum;

# float vs. double

浮點數值的精度代表該數值在小數點後能有多少位數。 float 的精度只有六到七位小數,而 double 變數的精度約為 15 位。因此,大多數計算情況下使用 double 較為安全。

# 科學記號數字

浮點數也可以是使用 "e" 表示 10 的次方的科學記號數字:

float f1 = 35e3;
double d1 = 12E4;
cout << f1;
cout << d1;

# 布林資料型態(Boolean Data Types)

布林資料型態以 bool 關鍵字宣告,只能有 true 或 false 兩種值。

當這個值被回傳時, true = 1 , false = 0 。

bool isCodingFun = true;
bool isFishTasty = false;
cout << isCodingFun; // Outputs 1 (true)
cout << isFishTasty; // Outputs 0 (false)

布林值大多用於條件判斷測試,這會在之後的章節詳細說明。

# 字元資料型態(Character Data Types)

char 資料型態用來儲存單一字元。字元必須用單引號包起來,例如 'A' 或 'c':

char myGrade = 'B';
cout << myGrade;

如果你熟悉 ASCII,也可以使用 ASCII 值來顯示特定字元:

char a = 65, b = 66, c = 67;
cout << a;
cout << b;
cout << c;

# 字串資料型態(String Data Types)

string 型態用來儲存一連串的字元(文字)。這不是 C++ 的內建型態,但在最基本的用法上它的行為就像內建型態一樣。字串的值必須用雙引號包起來:

string greeting = "Hello";
cout << greeting;

要使用字串,必須在原始碼中額外引入 <string> 標頭檔函式庫:

// Include the string library
#include <string>
// Create a string variable
string greeting = "Hello";
// Output string value
cout << greeting;

# auto 關鍵字

auto 關鍵字會根據你賦予變數的值,自動判斷該變數的型態。

它能幫助你寫出更簡潔的程式碼,並避免重複撰寫型態,尤其是在型態較長或較複雜時特別有用。

舉例來說: 與其寫 int x = 5; ,你可以寫成:

auto x = 5; // x is automatically treated as int

從 C++11 開始, auto 成為讓編譯器根據所賦予的值自動判斷型態的強大工具。

以下範例展示 auto 如何根據賦予的值,建立不同型態的變數:

// Creating auto variables
auto myNum = 5; // int
auto myFloatNum = 5.99f; // float
auto myDoubleNum = 9.98; // double
auto myLetter = 'D'; // char
auto myBoolean = true; // bool
auto myString = string("Hello"); // std::string

# 重要注意事項

  • auto 只有在同時賦值的情況下才能運作(不能只宣告 auto x; 而不賦值)
  • 一旦型態被決定,就會固定不變,如以下範例:
auto x = 5; // x is now an int
x = 10; // OK - still an int
x = 9.99; // Error - can't assign a double to an int

注意: 在這份教學中,當型態簡單且容易辨識時,我們通常會使用 int 、 double 等基本型態。

但對於較複雜的型態,例如之後章節會學到的疊代器(iterators)與 lambda 運算式,我們會使用 auto 讓程式碼更簡潔、更容易理解。

# 實際案例

以下是使用不同資料型態的實際案例,計算並印出多項商品的總花費:

// Create variables of different data types
int items = 50;
double cost_per_item = 9.99;
double total_cost = items * cost_per_item;
char currency = '$';
// Print variables
cout << "Number of items: " << items << "\n";
cout << "Cost per item: " << cost_per_item << currency << "\n";
cout << "Total cost = " << total_cost << currency << "\n";

# C++ 運算子(Operators)

運算子用來對變數與數值執行運算。

以下範例中,我們使用 + 運算子將兩個值相加:

int x = 100 + 50;

雖然 + 運算子最常用於將兩個值相加(如上面的範例),但它也可以用於將變數與數值相加,或是將變數與另一個變數相加:

int sum1 = 100 + 50; // 150 (100 + 50)
int sum2 = sum1 + 250; // 400 (150 + 250)
int sum3 = sum2 + sum2; // 800 (400 + 400)

C++ 將運算子分為以下幾類:

  • 算術運算子(Arithmetic operators)
  • 賦值運算子(Assignment operators)
  • 比較運算子(Comparison operators)
  • 邏輯運算子(Logical operators)
  • 位元運算子(Bitwise operators)

# 算術運算子(Arithmetic Operators)

算術運算子用來執行常見的數學運算。

運算子 名稱 說明 範例
+ 加法 將兩個值相加 x + y
- 減法 從一個值減去另一個值 x - y
* 乘法 將兩個值相乘 x * y
/ 除法 將一個值除以另一個值 x / y
% 取餘數 回傳除法的餘數 x % y
++ 遞增 將變數的值加 1 ++x
-- 遞減 將變數的值減 1 --x

以下範例在同一個範例中使用了不同的算術運算子:

int x = 10;
int y = 3;
cout << (x + y) << "\n"; // 13
cout << (x - y) << "\n"; // 7
cout << (x * y) << "\n"; // 30
cout << (x / y) << "\n"; // 3 (integer division)
cout << (x % y) << "\n"; // 1
int z = 5;
++z;
cout << z << "\n"; // 6
--z;
cout << z << "\n"; // 5

注意: 在 C++ 中將兩個整數相除時,結果也會是整數。例如 10 / 3 會得到 3 。如果想要有小數的結果,需使用 float 或 double 值,例如 10.0 / 3 。

int x = 10;
int y = 3;
cout << (x / y) << "\n";   // Integer division, result is 3
double a = 10.0;
double b = 3.0;
cout << (a / b) << "\n";   // Decimal division, result is 3.333...

# 遞增與遞減

遞增與遞減在程式設計中非常常見,尤其是在使用計數器、迴圈與陣列時(會在之後的章節詳細說明)。

++ 運算子將值加 1, -- 運算子將值減 1:

int x = 5;
++x; // Increment x by 1
cout << x << "\n"; // 6
int x = 5;
--x; // Decrement x by 1
cout << x << "\n"; // 4

有時候你可能會同時對同一個變數做遞增與遞減。要記得,如果先增加一個值、之後再減少它,結果會先加 1 再減 1—— 最後會回到原本的值:

int x = 5;
++x; // Increment x by 1 (x becomes 6)
--x; // Decrement x by 1 (x becomes 5 again)
cout << x << "\n"; // 5

# 實際案例:計算人數

假設你正在寫一個程式,用來計算有多少人進出一個房間。可以用 ++ 在有人進來時增加計數器,用 -- 在有人離開時減少計數器:

int peopleInRoom = 0;
// 3 people enter
peopleInRoom++;
peopleInRoom++;
peopleInRoom++;
cout << peopleInRoom << "\n"; // 3
// 1 person leaves
peopleInRoom--;
cout << peopleInRoom << "\n"; // 2

# 賦值運算子(Assignment Operators)

賦值運算子用來將值賦予變數。

以下範例中,我們使用賦值運算子( = )將值 10 賦予名為 x 的變數:

int x = 10;

加法複合賦值運算子( += )會將一個值加到變數上:

int x = 10;
x += 5; // same as x = x + 5

所有賦值運算子清單:

運算子 範例 相當於
= x = 5 x = 5
+= x += 3 x = x + 3
-= x -= 3 x = x - 3
*= x *= 3 x = x * 3
/= x /= 3 x = x / 3
%= x %= 3 x = x % 3
&= x &= 3 x = x & 3
\|= x |= 3 x = x | 3
^= x ^= 3 x = x ^ 3
>>= x >>= 3 x = x >> 3
<<= x <<= 3 x = x << 3

# 複合賦值運算子

複合賦值運算子是一種較簡短的寫法,用於在賦值兩側都使用同一個變數的運算。例如,不用寫 x = x + 5; ,可以直接寫 x += 5; 。

int x = 10;
x += 5;  // same as x = x + 5
cout << x << "\n"; // 15
x *= 2;  // same as x = x * 2
cout << x << "\n"; // 30

小提示: 複合運算子讓程式碼更短、更易讀,尤其是在多次更新同一個變數時特別有用。

為什麼叫做「複合(Compound)」?

之所以稱為 複合賦值運算子,是因為它們把一般運算子(如 + 、 - 、 * 等)與賦值運算子( = )結合成一個單一運算子。例如, += 就是 + 與 = 的組合。

# 實際案例:追蹤存款

複合賦值運算子也可以用於實際情境。例如,可以用 += 運算子在存錢到帳戶時追蹤存款金額:

int savings = 100;
savings += 50; // add 50 to savings
cout << "Total savings: " << savings;

# 比較運算子(Comparison Operators)

比較運算子用來比較兩個值(或變數)。這在程式設計中很重要,因為它能幫助我們找出答案並做出判斷。

比較運算的回傳值是 1 或 0 ,代表 true(1)或 false(0)。這些值被稱為布林值(Boolean values),會在之後的 Booleans 與 If...Else 章節詳細說明。

以下範例中,我們使用大於運算子( > )來判斷 5 是否大於 3:

int x = 5;
int y = 3;
cout << (x > y); // returns 1 (true) because 5 is greater than 3

所有比較運算子清單:

運算子 名稱 範例
== 等於 x == y
!= 不等於 x != y
> 大於 x > y
< 小於 x < y
>= 大於等於 x >= y
<= 小於等於 x <= y

# 實際案例

比較運算子經常用於實際情境的條件判斷,例如檢查一個人的年齡是否足以投票:

int age = 18;
cout << (age >= 18) << "\n"; // 1 (true), old enough to vote
cout << (age < 18) << "\n";  // 0 (false)

另一個常見的用法是檢查密碼長度是否足夠:

int passwordLength = 5;
cout << (passwordLength >= 8) << "\n"; // 0 (false), too short
cout << (passwordLength < 8) << "\n";  // 1 (true), needs more characters

# 邏輯運算子(Logical Operators)

如同比較運算子一樣,你也可以使用邏輯運算子來測試 true( 1 )或 false( 0 )的值。

邏輯運算子用來判斷變數或值之間的邏輯關係:

運算子 名稱 說明 範例
&& 邏輯 and 兩個陳述式都為真時回傳 true x < 5 && x < 10
\|\| 邏輯 or 其中一個陳述式為真時回傳 true x < 5 || x < 4
! 邏輯 not 反轉結果,若結果為真則回傳 false !(x < 5 && x < 10)

之後的章節會更詳細說明 true 與 false 值。

# 運算子優先順序(Operator Precedence)

當一個運算式中包含超過一個運算子時,C++ 會依照 ** 運算順序(order of operations)** 規則來決定先計算哪個部分。

例如,乘法會先於加法計算:

int result1 = 2 + 3 * 4;     // 2 + 12 = 14
int result2 = (2 + 3) * 4;   // 5 * 4 = 20
cout << result1 << "\n";
cout << result2 << "\n";

# 為什麼會這樣?

在 2 + 3 * 4 中,乘法會先被計算,所以答案是 14 。

如果想讓加法先被計算,必須使用括號: (2 + 3) * 4 ,結果會是 20 。

小提示: 如果想確保運算按照你預期的順序進行,務必使用括號 ( ) 。這也能讓程式碼更容易閱讀。

# 運算順序

以下是 C++ 中一些常見運算子,依優先順序由高到低排列:

  • () - 括號
  • * 、 / 、 % - 乘法、除法、取餘數
  • + 、 - - 加法、減法
  • > 、 < 、 >= 、 <= - 比較
  • == 、 != - 相等判斷
  • && - 邏輯 AND
  • || - 邏輯 OR
  • = - 賦值

# 另一個範例

減法與加法會由左至右依序計算,除非加上括號:

int result1 = 10 - 2 + 5;    // (10 - 2) + 5 = 13
int result2 = 10 - (2 + 5);  // 10 - 7 = 3
cout << result1 << "\n";
cout << result2 << "\n";

記住: 括號永遠優先運算。使用括號來控制計算的順序。

# C++ 字串(Strings)

字串用來儲存文字/字元。

例如,"Hello World" 就是一個字串。

string 變數包含一連串用雙引號( "" )包起來的字元:

建立一個 string 型態的變數並賦值:

string greeting = "Hello";

要使用字串,必須在原始碼中額外引入 <string> 標頭檔函式庫:

// Include the string library
#include <string>
// Create a string variable
string greeting = "Hello";
// Print the string
cout << greeting;

注意: 字串可以包含多個單字、空格與標點符號:

string greeting = "Hello and welcome!";
cout << greeting;

# 字串串接(String Concatenation)

+ 運算子可以用在字串之間,將它們相加組成新的字串,這稱為串接(concatenation):

string firstName = "John ";
string lastName = "Doe";
string fullName = firstName + lastName;
cout << fullName;

上面的範例中,我們在 firstName 後面加了一個空格,讓輸出時 John 與 Doe 之間有空格。不過,也可以用引號另外加上空格( " " 或 ' ' ):

string firstName = "John";
string lastName = "Doe";
string fullName = firstName + " " + lastName;
cout << fullName;

# Append

C++ 中的字串其實是一個物件,內含可以對字串執行特定操作的函式。例如,也可以用 append() 函式來串接字串:

string firstName = "John ";
string lastName = "Doe";
string fullName = firstName.append(lastName);
cout << fullName;

# 數字與字串相加

警告!

C++ 對 + 運算子同時用於加法與串接。

數字會被相加,字串會被串接。

如果將兩個數字相加,結果會是一個數字:

int x = 10;
int y = 20;
int z = x + y; // z will be 30 (an integer)

如果將兩個字串相加,結果會是字串串接:

string x = "10";
string y = "20";
string z = x + y; // z will be 1020 (a string)

如果嘗試將數字加到字串上,會發生錯誤:

string x = "10";
int y = 20;
string z = x + y;

# 字串長度(String Length)

要取得字串的長度,可以使用 length() 函式:

string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
cout << "The length of the txt string is: " << txt.length();

小提示: 有些 C++ 程式會使用 size() 函式來取得字串長度,這只是 length() 的別名。你可以自行選擇要用 length() 還是 size() :

string txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
cout << "The length of the txt string is: " << txt.size();

# 存取字串(Access Strings)

可以透過方括號 [] 內的索引值來存取字串中的字元。

這個範例印出 myString 中的第一個字元:

string myString = "Hello";
cout << myString[0];
// Outputs H

注意: 字串索引從 0 開始:[0] 是第一個字元,[1] 是第二個字元,以此類推。

這個範例印出 myString 中的第二個字元:

string myString = "Hello";
cout << myString[1];
// Outputs e

要印出字串的最後一個字元,可以使用以下程式碼:

string myString = "Hello";
cout << myString[myString.length() - 1];
// Outputs o

# 修改字串字元

要修改字串中特定字元的值,可以透過索引值並使用單引號:

string myString = "Hello";
myString[0] = 'J';
cout << myString;
// Outputs Jello instead of Hello

# at() 函式

<string> 函式庫也有一個 at() 函式,可以用來存取字串中的字元:

string myString = "Hello";
cout << myString; // Outputs Hello
cout << myString.at(0); // First character
cout << myString.at(1); // Second character
cout << myString.at(myString.length() - 1); // Last character
myString.at(0) = 'J';
cout << myString; // Outputs Jello

# 特殊字元(Special Characters)

因為字串必須寫在引號內,以下這種字串寫法會讓 C++ 誤解,並產生錯誤:

string txt = "We are the so-called "Vikings" from the north.";

要避免這個問題,可以使用反斜線跳脫字元。

反斜線( \ )跳脫字元會把特殊字元轉換成字串字元:

跳脫字元 結果 說明
\' ' 單引號
\" " 雙引號
\\ \ 反斜線

\" 序列會在字串中插入雙引號:

string txt = "We are the so-called \"Vikings\" from the north.";

\' 序列會在字串中插入單引號:

string txt = "It\'s alright.";

\\ 序列會在字串中插入一個反斜線:

string txt = "The character \\ is called backslash.";

其他常見的 C++ 跳脫字元:

跳脫字元 結果
\n 換行
\t Tab

# 使用者輸入字串(User Input Strings)

可以在 cin 上使用擷取運算子 >> 來儲存使用者輸入的字串:

string firstName;
cout << "Type your first name: ";
cin >> firstName; // get user input from the keyboard
cout << "Your name is: " << firstName;
// Type your first name: John
// Your name is: John

不過, cin 會把空格(空白、tab 等)視為終止字元,這代表它只能儲存單一個單字(即使輸入了多個單字):

string fullName;
cout << "Type your full name: ";
cin >> fullName;
cout << "Your name is: " << fullName;
// Type your full name: John Doe
// Your name is: John

從上面的範例可以看到,雖然預期程式會印出 "John Doe",但實際上只印出了 "John"。

因此,在處理字串時,我們經常使用 getline() 函式來讀取一整行文字。它的第一個參數是 cin ,第二個參數是字串變數:

string fullName;
cout << "Type your full name: ";
getline (cin, fullName);
cout << "Your name is: " << fullName;
// Type your full name: John Doe
// Your name is: John Doe

# 省略命名空間

有些 C++ 程式會在沒有標準命名空間函式庫的情況下執行。 using namespace std 這一行可以省略,改為在 string (以及 cout )物件前加上 std 關鍵字與 :: 運算子:

#include <iostream>
#include <string>
// using namespace std; - Remove this line
int main() {
  std::string greeting = "Hello";
  std::cout << greeting;
  return 0;
}

是否要引入標準命名空間函式庫,取決於你自己的選擇。在這份教學中,我們會繼續引入該函式庫。

# C 風格字串(C-Style Strings)

C 風格字串是用 char 型態建立的,而不是 string 。

這個名稱來自 C 語言,因為 C 語言不像許多其他程式語言擁有可以輕鬆建立字串變數的 string 型態。取而代之,必須使用 char 型態並建立一個字元陣列(array)來組成 C 語言中的「字串」。

由於 C++ 是作為 C 語言的延伸而開發的,因此它延續了這種在 C++ 中建立字串的方式:

string greeting1 = "Hello"; // Regular String
char greeting2[] = "Hello"; // C-Style String (an array of characters)

注意: 使用標準的 string 型態會比使用 C 風格字串更方便。不過,有些使用者仍然使用 C 風格字串的其中一個原因,是因為它們可以使用 C 標準函式庫中的函式。

# C++ 數學(Math)

C++ 提供許多函式,讓你可以對數字執行數學運算。

# 最大值與最小值

max(x, y) 函式可以用來找出 x 與 y 中較大的值:

cout << max(5, 10);

min(x, y) 函式可以用來找出 x 與 y 中較小的值:

cout << min(5, 10);

# C++ <cmath> 函式庫

其他函式,例如 sqrt (平方根)、 round (四捨五入)與 log (自然對數),可以在 <cmath> 標頭檔中找到:

// Include the cmath library
#include <cmath>
cout << sqrt(64);
cout << round(2.6);
cout << log(2);

# C++ 布林值(Booleans)

在程式設計中,你經常會需要一種只能有兩種值之一的資料型態,例如:

  • YES / NO
  • ON / OFF
  • TRUE / FALSE

為此,C++ 提供了 bool 資料型態,其值可以是 true (1)或 false (0)。

# 布林值

布林變數以 bool 關鍵字宣告,其值可以是 true 或 false :

bool isCodingFun = true;
bool isFishTasty = false;
cout << isCodingFun << "\n";  // Outputs 1 (true)
cout << isFishTasty << "\n"; // Outputs 0 (false)

從上面的範例可以看出, true 值會回傳 1 , false 值會回傳 0 。

# 使用 boolalpha 印出 true/false

如果你希望印出 true 與 false 這樣的文字,而不是 1 與 0 ,可以使用 boolalpha 操縱器:

bool isCodingFun = true;
bool isFishTasty = false;
cout << boolalpha; // enable printing "true"/"false"
cout << isCodingFun << "\n";   // Outputs true
cout << isFishTasty << "\n";  // Outputs false

注意: boolalpha 不是一種資料型態,而是一種 I/O 操縱器(I/O manipulator)—— 用來改變 cout 顯示布林值方式的設定。當你使用它時,等於是在告訴 cout :「從現在開始,將布林值印成 true 與 false ,而不是 1 與 0 。」

# 用 noboolalpha 重設回預設值

如果想回到預設行為(印出 1 與 0 ),可以使用 noboolalpha :

bool isCodingFun = true;
cout << boolalpha;   // print as true/false
cout << isCodingFun << "\n";  // Outputs true
cout << noboolalpha; // reset to 1/0
cout << isCodingFun << "\n";  // Outputs 1

注意: 要用預設的 1 與 0 ,還是用文字 true 與 false ,取決於你自己的偏好。兩者在 C++ 中都是正確的寫法,且可以透過 boolalpha 與 noboolalpha 互相切換。

上面的範例都是使用固定的布林值。但在實際的程式中,布林值通常是比較數值或變數之後得到的結果,這會在下一節詳細說明。

# 布林運算式(Boolean Expressions)

布林運算式(Boolean expression) 是一段用來比較數值或變數,並回傳布林值 1 (true)或 0 (false)的程式碼。

布林運算式是程式設計中做決策的基礎 —— 它們讓程式能根據某件事是真是假來決定要做什麼。

可以使用比較運算子,例如大於( > )運算子,來判斷一個運算式(或變數)是真還是假:

int x = 10;
int y = 9;
cout << (x > y); // returns 1 (true), because 10 is higher than 9

或是更簡單地:

cout << (10 > 9); // returns 1 (true), because 10 is higher than 9

以下範例使用等於( == )運算子來計算運算式的結果:

int x = 10;
cout << (x == 10); // returns 1 (true), because the value of x is equal to 10
cout << (10 == 15); // returns 0 (false), because 10 is not equal to 15

# 將結果存進布林變數

也可以把比較的結果存進一個 bool 變數:

將 x > y 的比較結果存進布林變數,並印出它:

int x = 10;
int y = 9;
bool isGreater = x > y;
cout << isGreater; // returns 1 (true)

注意: 是否要把比較結果存成布林變數,或是直接使用比較運算,取決於你自己。將結果存起來可以讓程式碼更容易閱讀,尤其是想要重複使用該結果時。

# 實際案例

讓我們用一個實際案例來使用布林值,判斷一個人的年齡是否足以投票。

以下範例中,我們使用 >= 比較運算子,判斷年齡( 25 )是否大於或等於投票年齡限制 18 :

int myAge = 25;
int votingAge = 18;
cout << (myAge >= votingAge); // returns 1 (true), meaning 25 year olds are allowed to vote!

更好的做法(既然我們已經上手了),是把上面的程式碼包進 if...else 陳述式中,這樣就能依照結果執行不同的動作:

如果 myAge 大於或等於 18 ,就輸出 "Old enough to vote!",否則輸出 "Not old enough to vote.":

int myAge = 25;
int votingAge = 18;
if (myAge >= votingAge) {
  cout << "Old enough to vote!";
} else {
  cout << "Not old enough to vote.";
}
// Outputs: Old enough to vote!

布林值是所有 C++ 比較與條件判斷的基礎。之後的章節會詳細說明條件判斷( if...else )。

# C++ If...Else

前面已經知道 C++ 支援數學上熟悉的比較條件,例如:

  • 小於:a < b
  • 小於等於:a <= b
  • 大於:a > b
  • 大於等於:a >= b
  • 等於:a == b
  • 不等於:a != b

這些條件用來根據某件事是真或假,來執行不同的動作。

C++ 有以下幾種條件陳述式:

  • 使用 if 指定一段程式碼區塊,在條件為真時執行
  • 使用 else 指定一段程式碼區塊,在同一個條件為假時執行
  • 使用 else if 指定一個新的條件,在第一個條件為假時測試
  • 使用 switch 指定多個可供選擇的程式碼區塊

# if 陳述式

使用 if 陳述式來指定一段 C++ 程式碼區塊,在條件為 true 時執行。

語法:

if (condition) {
  // block of code to be executed if the condition is true
}

注意 if 必須以小寫字母書寫,若寫成大寫( If 或 IF )會產生錯誤。

以下範例測試兩個值,判斷 20 是否大於 18。如果條件為 true ,就印出訊息:

if (20 > 18) {
  cout << "20 is greater than 18";
}

也可以在條件中使用變數:

int x = 20;
int y = 18;
if (x > y) {
  cout << "x is greater than y";
}

上面的範例中,我們使用兩個變數 x 與 y,測試 x 是否大於 y。因為 20 大於 18,條件為真,所以印出了訊息。

# 使用布林變數

由於 if 陳述式的條件必須是 true 或 false,你可以將結果存進一個布林變數,而不用直接寫比較運算:

int x = 20;
int y = 18;
bool isGreater = x > y;
if (isGreater) {
  cout << "x is greater than y";
}

這樣可以讓程式碼更容易閱讀,尤其是條件較複雜或會重複使用時。

# else 陳述式

使用 else 陳述式來指定一段程式碼區塊,在條件為 false 時執行。

語法:

if (condition) {
  // block of code to be executed if the condition is true
} else {
  // block of code to be executed if the condition is false
}

以下範例中,程式檢查 time 的值。如果小於 18,就印出 "Good day.";否則印出 "Good evening.":

int time = 20;
if (time < 18) {
  cout << "Good day.";
} else {
  cout << "Good evening.";
}
// Outputs "Good evening."

因為 time 是 20,所以條件 time < 18 為假,因此執行了 else 區塊內的程式碼,印出 "Good evening."。如果 time 小於 18,程式就會印出 "Good day."。

# 使用布林變數

也可以把條件存進布林變數,並在 if...else 陳述式中使用它,這樣能讓程式碼更容易閱讀:

int time = 20;
bool isDay = time < 18;
if (isDay) {
  cout << "Good day.";
} else {
  cout << "Good evening.";
}
// Outputs "Good evening."

小提示: 像 isDay 這樣的名稱,能讓人容易理解這個條件代表的意思。

# else if 陳述式

使用 else if 陳述式,在第一個條件為 false 時,指定一個新的條件進行測試。

可以使用 else if 依序檢查多個條件。

語法:

if (condition1) {
  // block of code to be executed if condition1 is true
} else if (condition2) {
  // block of code to be executed if condition1 is false and condition2 is true
} else {
  // block of code to be executed if both conditions are false
}

這些條件會由上到下依序檢查。一旦某個條件為 true ,就會執行對應的程式碼區塊,其餘的條件則會被跳過。

# 範例

以下範例依照 time 的值,決定要印出哪一則訊息:

int time = 16;
if (time < 12) {
  cout << "Good morning.";
} else if (time < 18) {
  cout << "Good day.";
} else {
  cout << "Good evening.";
}
// Outputs "Good day."

time 的值是 16。第一個條件( time < 12 )為假,但第二個條件( time < 18 )為真。因此執行了 else if 區塊中的程式碼,印出 "Good day."。

如果 time 的值是 22,所有條件都會是假,程式就會印出 "Good evening."。

# 使用布林變數

與 if 陳述式一樣,也可以把條件存進布林變數,並搭配 else if 使用:

int time = 16;
bool isMorning = time < 12;
bool isDay = time < 18;
if (isMorning) {
  cout << "Good morning.";
} else if (isDay) {
  cout << "Good day.";
} else {
  cout << "Good evening.";
}

小提示: 像 isMorning 與 isDay 這樣的布林變數名稱,能讓人更容易理解每個條件代表的意思。

# 簡寫 If...Else(三元運算子)

還有一種 if...else 的簡寫形式,稱為三元運算子(ternary operator),因為它使用了三個運算元。

三元運算子會根據條件_回傳一個值_:如果條件為 true ,就回傳第一個值;否則回傳第二個值。

它可以用來將多行程式碼簡化成一行,通常用來取代簡單的 if...else 陳述式:

語法:

variable = (condition) ? expressionTrue : expressionFalse;

與其寫成:

int time = 20;
if (time < 18) {
  cout << "Good day.";
} else {
  cout << "Good evening.";
}

可以直接簡化成:

int time = 20;
string result = (time < 18) ? "Good day." : "Good evening.";
cout << result;

也可以直接在 cout 陳述式中使用三元運算子:

int time = 20;
cout << ((time < 18) ? "Good day." : "Good evening.");

小提示: 三元運算子適合用在簡短、簡單的條件。若邏輯較長或複雜,一般的 if...else 陳述式會更容易閱讀。

# 巢狀三元運算子

可以巢狀使用三元運算子來處理兩種以上的結果,但這會讓程式碼較難閱讀:

int time = 22;
string message = (time < 12) ? "Good morning."
: (time < 18) ? "Good afternoon."
: "Good evening.";
cout << message;

注意: 雖然巢狀三元運算子可以運作,但為了清楚易讀,通常建議使用一般的 if...else if...else 陳述式。

# 巢狀 if(Nested If)

也可以把一個 if 陳述式放進另一個 if 裡面,這稱為 ** 巢狀 if(nested if)** 陳述式。

巢狀 if 讓你只有在另一個條件已經為 true 時,才去檢查某個條件。

語法:

if (condition1) {
  // code to run if condition1 is true
  if (condition2) {
    // code to run if both condition1 and condition2 are true
  }
}

# 範例

這個範例中,我們先檢查 x 是否大於 10,如果是,才接著檢查 y 是否大於 20:

int x = 15;
int y = 25;
if (x > 10) {
  cout << "x is greater than 10\n";
  // Nested if
  if (y > 20) {
    cout << "y is also greater than 20\n";
  }
}

# 實際案例

巢狀 if 陳述式適合用在需要測試多個彼此相依的條件時。例如,檢查一個人的年齡是否足以投票,並且是否為公民:

int age = 20;
bool isCitizen = true;
if (age >= 18) {
  cout << "Old enough to vote.\n";
  if (isCitizen) {
    cout << "And you are a citizen, so you can vote!\n";
  } else {
    cout << "But you must be a citizen to vote.\n";
  }
} else {
  cout << "Not old enough to vote.\n";
}

# 注意事項

  • 可以巢狀使用任意數量的 if 陳述式,但要避免巢狀層數太深,否則會變得難以閱讀。
  • 巢狀 if 經常與 else 和 else if 搭配使用,以進行更複雜的決策判斷。

# 條件判斷中的邏輯運算子

可以使用邏輯運算子來組合或反轉條件,這些運算子可以與 if 、 else 、 else if 一起使用,建立更複雜的判斷。

  • && (AND)—— 所有條件都必須為真
  • || (OR)—— 至少一個條件為真即可
  • ! (NOT)—— 反轉條件( true → false , false → true )

# AND( && )

當兩個條件都必須為真時,使用 AND( && ):

測試 a 是否大於 b ,並且 c 是否大於 a :

int a = 200;
int b = 33;
int c = 500;
if (a > b && c > a) {
  cout << "Both conditions are true";
}

# OR( || )

當至少一個條件為真即可時,使用 OR( || ):

測試 a 是否大於 b ,或者 a 是否大於 c :

int a = 200;
int b = 33;
int c = 500;
if (a > b || a > c) {
  cout << "At least one condition is true";
}

# NOT( ! )

NOT 運算子( ! )會反轉一個條件:

  • 如果條件為 true , ! 會讓它變成 false 。
  • 如果條件為 false , ! 會讓它變成 true 。

這在你想要確認某件事「並非如此」時很有用:

測試 a 是否不大於 b :

int a = 33;
int b = 200;
if (!(a > b)) {
  cout << "a is NOT greater than b";
}

# 實際案例

在實際的程式中,邏輯運算子經常用於存取權限控管。例如,要取得系統存取權限,會有特定的條件:

必須已經登入,並且需要是管理員,或是擁有較高的安全等級(1 級或 2 級):

bool isLoggedIn = true;
bool isAdmin = false;
int securityLevel = 3; // 1 = highest
if (isLoggedIn && (isAdmin || securityLevel <= 2)) {
  cout << "Access granted.";
} else {
  cout << "Access denied.";
}
// Try changing securityLevel and isAdmin to test different outcomes:
// securityLevel 1 = Access granted
// securityLevel 2 = Access granted
// securityLevel 3 = Access denied
// securityLevel 4 = Access denied
// If isAdmin = true, access is granted.

# 實際案例集

這個範例展示如何使用 if...else ,在使用者輸入正確代碼時「打開一扇門」:

int doorCode = 1337;
if (doorCode == 1337) {
  cout << "Correct code.\nThe door is now open.\n";
} else {
  cout << "Wrong code.\nThe door remains closed.\n";
}

這個範例展示如何使用 if...else 判斷一個數字是正數還是負數:

int myNum = 10; // Is this a positive or negative number?
if (myNum > 0) {
  cout << "The value is a positive number.\n";
} else if (myNum < 0) {
  cout << "The value is a negative number.\n";
} else {
  cout << "The value is 0.\n";
}

判斷一個人的年齡是否足以投票:

int myAge = 25;
int votingAge = 18;
if (myAge >= votingAge) {
  cout << "Old enough to vote!\n";
} else {
  cout << "Not old enough to vote.\n";
}

判斷一個人的年齡是否足以投票,並且是否為公民(使用巢狀 if 陳述式):

int age = 20;
bool isCitizen = true;
if (age >= 18) {
  cout << "Old enough to vote.\n";
  if (isCitizen) {
    cout << "And you are a citizen, so you can vote!\n";
  } else {
    cout << "But you must be a citizen to vote.\n";
  }
} else {
  cout << "Not old enough to vote.\n";
}

判斷一個數字是偶數還是奇數:

int myNum = 5;
if (myNum % 2 == 0) {
  cout << myNum << " is even.\n";
} else {
  cout << myNum << " is odd.\n";
}

檢查溫度(攝氏):

int temperature = 30;
if (temperature < 0) {
  cout << "It's freezing!\n";
} else if (temperature < 20) {
  cout << "It's cool.\n";
} else {
  cout << "It's warm.\n";
}

# C++ Switch

使用 switch 陳述式,從多個程式碼區塊中選擇一個來執行。

語法:

switch(expression) {
  case x:
    // code block
    break;
  case y:
    // code block
    break;
  default:
    // code block
}

運作方式如下:

  • switch 運算式只會被計算一次
  • 這個運算式的值會與每個 case 的值進行比較
  • 如果找到相符的值,就會執行對應的程式碼區塊
  • break 與 default 關鍵字是可選的,會在本節稍後說明

以下範例使用星期數字來計算星期名稱:

int day = 4;
switch (day) {
  case 1:
    cout << "Monday";
    break;
  case 2:
    cout << "Tuesday";
    break;
  case 3:
    cout << "Wednesday";
    break;
  case 4:
    cout << "Thursday";
    break;
  case 5:
    cout << "Friday";
    break;
  case 6:
    cout << "Saturday";
    break;
  case 7:
    cout << "Sunday";
    break;
}
// Outputs "Thursday" (day 4)

# break 關鍵字

當 C++ 執行到 break 關鍵字時,就會跳出 switch 區塊。

這會停止繼續執行區塊內其餘的程式碼與 case 判斷。

一旦找到相符的結果、任務完成了,就該使用 break,不需要再進行其餘的測試。

break 可以節省大量的執行時間,因為它會「忽略」執行 switch 區塊中剩下的所有程式碼。

# default 關鍵字

default 關鍵字用來指定在沒有任何 case 相符時要執行的程式碼:

int day = 4;
switch (day) {
  case 6:
    cout << "Today is Saturday";
    break;
  case 7:
    cout << "Today is Sunday";
    break;
  default:
    cout << "Looking forward to the Weekend";
}
// Outputs "Looking forward to the Weekend"

# C++ 迴圈(Loops)

只要指定的條件成立,迴圈就能重複執行一段程式碼。

迴圈很方便,因為它們能節省時間、減少錯誤,並讓程式碼更容易閱讀。

# C++ While 迴圈

只要指定的條件為 true , while 迴圈就會重複執行一段程式碼:

語法:

while (condition) {
  // code block to be executed
}

以下範例中,只要變數 i 小於 5,迴圈內的程式碼就會不斷重複執行:

int i = 0;
while (i < 5) {
  cout << i << "\n";
  i++;
}

注意: 別忘了要增加條件中使用的變數( i++ ),否則迴圈永遠不會結束!

你可能好奇為什麼常用字母 i 作為變數名稱?這是一個計數器變數,在簡單迴圈中很常見,因為它簡短、傳統,且代表 'index'(索引)或 'iterator'(疊代器)。

# 倒數計時範例

這個範例從 3 倒數到 1,最後印出 "Happy New Year!!":

int countdown = 3;
while (countdown > 0) {
  cout << countdown << "\n";
  countdown--;
}
cout << "Happy New Year!!\n";

# Do/While 迴圈

do/while 迴圈是 while 迴圈的一種變形。這種迴圈會先執行一次程式碼區塊,再檢查條件是否為真,接著只要條件為真就會持續重複執行。

語法:

do {
  // code block to be executed
}
while (condition);

注意: while 條件後面的分號 ; 是必要的!

# Do/While 範例

以下範例使用 do/while 迴圈。因為程式碼區塊會在條件測試之前先執行,所以這個迴圈至少會執行一次,即使條件一開始就是 false。

int i = 0;
do {
  cout << i << "\n";
  i++;
}
while (i < 5);

別忘了要增加條件中使用的變數( i++ ),否則迴圈永遠不會結束!

# 條件一開始就是 False

上面的範例中,條件 i < 5 一開始就是 true,所以迴圈重複執行了多次。但如果條件一開始就是 false 呢?

以下範例中,變數 i 一開始就是 10 ,所以條件 i < 5 一開始就是假的 —— 但 do/while 迴圈仍然會執行一次:

int i = 10;
do {
  cout << "i is " << i << "\n";
  i++;
} while (i < 5);

# 小結

do/while 迴圈至少會執行一次,即使條件一開始就是假的。這與一般的 while 迴圈不同, while 迴圈如果一開始條件就是假的,就會完全跳過整個迴圈。

這個特性讓 do/while 在你希望某件事至少發生一次時很有用,例如顯示訊息或要求使用者輸入。

# 實際案例:使用者輸入

這個範例會不斷要求使用者輸入一個正數,當使用者輸入 0 或負數時迴圈就會停止:

int number;
do {
  cout << "Enter a positive number: ";
  cin >> number;
} while (number > 0);

# 實際案例

展示 while 迴圈的實際應用,這裡建立了一個簡單的「倒數計時」程式:

int countdown = 3;
while (countdown > 0) {
  cout << countdown << "\n";
  countdown--;
}
cout << "Happy New Year!!\n";

這個範例建立一個只印出 0 到 10(含)之間偶數的程式:

int i = 0;
while (i <= 10) {
  cout << i << "\n";
  i += 2;
}

這個範例使用 while 迴圈來反轉一些數字:

// A variable with some specific numbers
int numbers = 12345;
// A variable to store the reversed number
int revNumbers = 0;
// Reverse and reorder the numbers
while (numbers) {
  // Get the last number of 'numbers' and add it to 'revNumbers'
  revNumbers = revNumbers * 10 + numbers % 10;
  // Remove the last number of 'numbers'
  numbers /= 10;
}
cout << "Reversed numbers: " << revNumbers << "\n";

展示 while 迴圈結合 if else 陳述式的實際應用,假設我們正在玩一場快艇骰子(Yatzy)遊戲:

int dice = 1;
while (dice <= 6) {
  if (dice < 6) {
    cout << "No Yatzy\n";
  } else {
    cout << "Yatzy!\n";
  }
  dice = dice + 1;
}

如果迴圈跑過 1 到 5 之間的值,就印出 "No Yatzy";每當跑到值 6 時,就印出 "Yatzy!"。

# C++ For 迴圈

當你確切知道要重複執行一段程式碼多少次時,可以使用 for 迴圈來取代 while 迴圈:

語法:

for (statement 1; statement 2; statement 3) {
  // code block to be executed
}

陳述式 1 會在程式碼區塊開始執行之前執行(一次)。

陳述式 2 定義了執行程式碼區塊的條件。

陳述式 3 會在程式碼區塊每次執行完之後執行。

# 印出數字

以下範例會印出數字 0 到 4:

for (int i = 0; i < 5; i++) {
  cout << i << "\n";
}

範例解說

  • 陳述式 1 在迴圈開始前設定一個變數: int i = 0
  • 陳述式 2 定義了迴圈執行的條件: i < 5 。如果條件為真,迴圈會再重新執行一次;如果為假,迴圈就會結束。
  • 陳述式 3 會在迴圈內的程式碼區塊每次執行後,增加一個值: i++

# 印出偶數

這個範例印出 0 到 10 之間的偶數:

for (int i = 0; i <= 10; i = i + 2) {
  cout << i << "\n";
}

# 數字加總

這個範例計算 1 到 5 之間數字的總和:

int sum = 0;
for (int i = 1; i <= 5; i++) {
  sum = sum + i;
}
cout << "Sum is " << sum;

# 倒數計時

這個範例印出從 5 到 1 的倒數:

for (int i = 5; i > 0; i--) {
  cout << i << "\n";
}

# 巢狀迴圈(Nested Loops)

也可以把一個迴圈放進另一個迴圈裡面,這稱為巢狀迴圈(nested loop)。

「內層迴圈」會在「外層迴圈」的每一次迭代中執行一次:

// Outer loop
for (int i = 1; i <= 2; ++i) {
  cout << "Outer: " << i << "\n"; // Executes 2 times
  // Inner loop
  for (int j = 1; j <= 3; ++j) {
    cout << " Inner: " << j << "\n"; // Executes 6 times (2 * 3)
  }
}

# 九九乘法表範例

這個範例使用巢狀迴圈印出一個簡單的乘法表(1 到 3):

for (int i = 1; i <= 3; i++) {
  for (int j = 1; j <= 3; j++) {
    cout << i * j << " ";
  }
  cout << "\n";
}

結果:

1 2 3
2 4 6
3 6 9

巢狀迴圈適合用在處理表格、矩陣或多維資料結構時。

# foreach 迴圈

還有一種「for-each 迴圈」(也稱為範圍式 for 迴圈,ranged-based for loop),用來走訪陣列(或其他資料結構)中的元素:

語法:

for (type variableName : arrayName) {
  // code block to be executed
}

以下範例使用「for-each 迴圈」輸出陣列中的所有元素:

int myNumbers[5] = {10, 20, 30, 40, 50};
for (int num : myNumbers) {
  cout << num << "\n";
}

# 走訪字串

也可以使用 for-each 迴圈來走訪字串中的字元:

string word = "Hello";
for (char c : word) {
  cout << c << "\n";
}

注意: 如果還看不太懂上面的範例也沒關係,之後在 Arrays 章節會詳細說明陣列。

補充知識: for-each 迴圈是在 C++11(2011 年)版本中引入的。

# 實際案例

展示 for 迴圈的實際應用,建立一個以 10 為間隔數到 100 的程式:

for (int i = 0; i <= 100; i += 10) {
  cout << i << "\n";
}

這個範例建立一個只印出 0 到 10(含)之間偶數的程式:

for (int i = 0; i <= 10; i = i + 2) {
  cout << i << "\n";
}

這裡我們只印出奇數:

for (int i = 1; i <= 10; i = i + 2) {
  cout << i << "\n";
}

這個範例印出 2 的次方直到 512:

for (int i = 2; i <= 512; i *= 2) {
  cout << i << "\n";
}

這個範例建立一個程式,印出指定數字的乘法表:

int number = 2;
int i;
// Print the multiplication table for the number 2
for (i = 1; i <= 10; i++) {
  cout << number << " x " << i << " = " << number * i << "\n";
}

# C++ Break 與 Continue

前面章節已經看過 break 陳述式的用法,它用來「跳出」 switch 陳述式。

break 陳述式也可以用來跳出迴圈。

以下範例在 i 等於 4 時跳出迴圈:

for (int i = 0; i < 10; i++) {
  if (i == 4) {
    break;
  }
  cout << i << "\n";
}

# C++ Continue

continue 陳述式會在符合指定條件時中斷(迴圈的)一次迭代,並繼續進行下一次迭代。

這個範例會跳過值 4:

for (int i = 0; i < 10; i++) {
  if (i == 4) {
    continue;
  }
  cout << i << "\n";
}

# 在 While 迴圈中使用 Break 與 Continue

break 與 continue 也可以用在 while 迴圈中:

# Break 範例

int i = 0;
while (i < 10) {
  cout << i << "\n";
  i++;
  if (i == 4) {
    break;
  }
}

# Continue 範例

int i = 0;
while (i < 10) {
  if (i == 4) {
    i++;
    continue;
  }
  cout << i << "\n";
  i++;
}

# C++ 陣列(Arrays)

陣列用來在單一變數中儲存多個值,而不用為每個值宣告個別的變數。

要宣告陣列,需定義變數型態,接著指定陣列名稱、後面加上方括號,並指定要儲存的元素數量:

string cars[4];

現在我們宣告了一個可以存放四個字串的陣列變數。要插入值,可以使用陣列字面值(array literal)—— 把值用逗號分隔,放在大括號內:

string cars[4] = {"Volvo", "BMW", "Ford", "Mazda"};

要建立一個含有三個整數的陣列,可以這樣寫:

int myNum[3] = {10, 20, 30};

# 存取陣列元素

透過方括號 [] 內的索引值來存取陣列元素。

以下陳述式存取 cars 中第一個元素的值:

string cars[4] = {"Volvo", "BMW", "Ford", "Mazda"};
cout << cars[0];
// Outputs Volvo

注意: 陣列索引從 0 開始:[0] 是第一個元素,[1] 是第二個元素,以此類推。

# 修改陣列元素

要修改特定元素的值,可以透過索引值來指定:

cars[0] = "Opel";
string cars[4] = {"Volvo", "BMW", "Ford", "Mazda"};
cars[0] = "Opel";
cout << cars[0];
// Now outputs Opel instead of Volvo

# 走訪陣列(Arrays and Loops)

可以使用 for 迴圈走訪陣列元素。

以下範例輸出 cars 陣列中的所有元素:

// Create an array of strings
string cars[5] = {"Volvo", "BMW", "Ford", "Mazda", "Tesla"};
// Loop through strings
for (int i = 0; i < 5; i++) {
  cout << cars[i] << "\n";
}

這個範例把每個元素的索引與值一起輸出:

string cars[5] = {"Volvo", "BMW", "Ford", "Mazda", "Tesla"};
for (int i = 0; i < 5; i++) {
  cout << i << " = " << cars[i] << "\n";
}

這個範例展示如何走訪一個整數陣列:

int myNumbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
  cout << myNumbers[i] << "\n";
}

# foreach 迴圈

還有一種「for-each 迴圈」(在 C++11(2011 年)引入),專門用來走訪陣列(以及其他資料結構,如 vector 與 list)中的元素:

語法:

for (type variableName : arrayName) {
  // code block to be executed
}

以下範例使用「for-each 迴圈」輸出陣列中的所有元素:

走訪整數:

// Create an array of integers
int myNumbers[5] = {10, 20, 30, 40, 50};
// Loop through integers
for (int num : myNumbers) {
  cout << num << "\n";
}

走訪字串:

// Create an array of strings
string cars[5] = {"Volvo", "BMW", "Ford", "Mazda", "Tesla"};
// Loop through strings
for (string car : cars) {
  cout << car << "\n";
}

# 省略陣列大小

在 C++ 中,不一定要指定陣列的大小。編譯器能根據插入的值的數量,自動判斷陣列的大小:

string cars[] = {"Volvo", "BMW", "Ford"}; // Three array elements

上面的範例等同於:

string cars[3] = {"Volvo", "BMW", "Ford"}; // Also three array elements

不過,後者的寫法被認為是「較佳做法」,因為它能降低程式出錯的機率。

# 宣告時省略元素

也可以在宣告陣列時不指定元素,稍後再加入:

string cars[5];
cars[0] = "Volvo";
cars[1] = "BMW";
cars[2] = "Ford";
cars[3] = "Mazda";
cars[4] = "Tesla";

注意: 上面的範例只有在已指定陣列大小時才能運作。

如果沒有指定陣列大小,就會發生錯誤:

string cars[]; // Array size is not specified
cars[0] = "Volvo";
cars[1] = "BMW";
cars[2] = "Ford";
cars[3] = "Mazda";
cars[4] = "Tesla";
// error: array size missing in 'cars'

# 固定大小(陣列)vs. 動態大小(向量)

在討論 C++ 陣列時,經常會聽到「固定大小」與「動態大小」這兩個詞。

這是因為 C++ 中陣列的大小是固定的,代表在陣列建立之後,你無法新增或移除元素。

陣列 —— 固定大小範例:

// An array with 3 elements
string cars[3] = {"Volvo", "BMW", "Ford"};
// Trying to add another element (a fourth element) to the cars array will result in an error
cars[3] = "Tesla";

# 向量(Vectors)

對於需要新增與移除陣列元素的操作,C++ 提供了向量(vectors),也就是可調整大小的陣列。

向量的大小是動態的,代表它可以依需求增長或縮小。

向量位於 <vector> 函式庫中,並提供許多實用的函式來新增、移除與修改元素:

向量 —— 動態大小範例:

// A vector with 3 elements
vector<string> cars = {"Volvo", "BMW", "Ford"};
// Adding another element to the vector
cars.push_back("Tesla");

這只是對向量的簡單介紹,讓你知道「可調整大小的陣列」是存在的。如果還看不懂上面的語法也沒關係,之後的章節會詳細說明向量與其他資料結構。

# 取得陣列大小

要取得陣列的大小,可以使用 sizeof() 運算子:

int myNumbers[5] = {10, 20, 30, 40, 50};
cout << sizeof(myNumbers);

為什麼結果顯示的是 20 而不是 5 ,明明陣列只有 5 個元素?

這是因為 sizeof() 運算子回傳的是型態的大小,單位是位元組(bytes)。

在 Data Types 章節學過, int 型態通常是 4 個位元組,所以上面範例中,4 x 5(4 位元組 x 5 個元素)= 20 個位元組。

要找出陣列中有多少個元素,必須將陣列的總大小除以陣列第一個元素的大小:

int myNumbers[5] = {10, 20, 30, 40, 50};
int getArrayLength = sizeof(myNumbers) / sizeof(myNumbers[0]);
cout << getArrayLength;

# 用 sizeof () 走訪陣列

在「走訪陣列」章節中,我們把陣列大小直接寫在迴圈條件裡( i < 5 )。這不是理想的做法,因為它只適用於特定大小的陣列。

不過,利用上面範例中的 sizeof() 方法,我們可以寫出適用於任何大小陣列的迴圈,這樣更具持續性。

與其寫成:

int myNumbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < 5; i++) {
  cout << myNumbers[i] << "\n";
}

更好的寫法是:

int myNumbers[5] = {10, 20, 30, 40, 50};
for (int i = 0; i < sizeof(myNumbers) / sizeof(myNumbers[0]); i++) {
  cout << myNumbers[i] << "\n";
}

注意,在 C++11(2011 年)中,也可以使用「for-each」迴圈,寫法更簡潔清楚:

int myNumbers[5] = {10, 20, 30, 40, 50};
for (int num : myNumbers) {
  cout << num << "\n";
}

了解走訪陣列的不同方式是有幫助的,因為在不同的程式中都可能會遇到它們。

# 實際案例

展示陣列的實際應用,建立一個計算不同年齡平均值的程式:

// An array storing different ages
int ages[8] = {20, 22, 18, 35, 48, 26, 87, 70};
float avg, sum = 0;
int i;
// Get the length of the array
int length = sizeof(ages) / sizeof(ages[0]);
// Loop through the elements of the array
for (int age : ages) {
  sum += age;
}
// Calculate the average by dividing the sum by the length
avg = sum / length;
// Print the average
cout << "The average age is: " << avg << "\n";

這個範例建立一個程式,找出不同年齡中最小的年齡:

// An array storing different ages
int ages[8] = {20, 22, 18, 35, 48, 26, 87, 70};
int i;
// Create a variable and assign the first array element of ages to it
int lowestAge = ages[0];
// Loop through the elements of the ages array to find the lowest age
for (int age : ages) {
  if (lowestAge > age) {
    lowestAge = age;
  }
}
// Print the lowest age
cout << "The lowest age is: " << lowestAge << "\n";

# 多維陣列(Multi-Dimensional Arrays)

多維陣列是「陣列的陣列」。

要宣告多維陣列,需定義變數型態,接著指定陣列名稱,後面加上方括號指定主陣列有多少元素,再加上另一組方括號指定子陣列有多少元素:

string letters[2][4];

與一般陣列一樣,可以用陣列字面值來插入值 —— 用逗號分隔、放在大括號中的清單。在多維陣列中,陣列字面值裡的每個元素本身又是另一個陣列字面值。

string letters[2][4] = {
  { "A", "B", "C", "D" },
  { "E", "F", "G", "H" }
};

陣列宣告中的每一組方括號都會為陣列增加一個維度。像上面這樣的陣列稱為擁有兩個維度。

陣列可以有任意數量的維度,維度越多,程式碼就越複雜。以下陣列有三個維度:

string letters[2][2][2] = {
  {
    { "A", "B" },
    { "C", "D" }
  },
  {
    { "E", "F" },
    { "G", "H" }
  }
};

# 存取多維陣列的元素

要存取多維陣列的元素,需要在陣列的每個維度中都指定一個索引值。

以下陳述式存取 letters 陣列中 ** 第一列(0)與第三行(2)** 的元素值:

string letters[2][4] = {
  { "A", "B", "C", "D" },
  { "E", "F", "G", "H" }
};
cout << letters[0][2]; // Outputs "C"

記住: 陣列索引從 0 開始:[0] 是第一個元素,[1] 是第二個元素,以此類推。

# 修改多維陣列的元素

要修改元素的值,需在每個維度中指定該元素的索引值:

string letters[2][4] = {
  { "A", "B", "C", "D" },
  { "E", "F", "G", "H" }
};
letters[0][0] = "Z";
cout << letters[0][0]; // Now outputs "Z" instead of "A"

# 走訪多維陣列

要走訪多維陣列,需要為陣列的每一個維度各設一個迴圈。

以下範例輸出 letters 陣列中的所有元素:

string letters[2][4] = {
  { "A", "B", "C", "D" },
  { "E", "F", "G", "H" }
};
for (int i = 0; i < 2; i++) {
  for (int j = 0; j < 4; j++) {
    cout << letters[i][j] << "\n";
  }
}

這個範例展示如何走訪一個三維陣列:

string letters[2][2][2] = {
  {
    { "A", "B" },
    { "C", "D" }
  },
  {
    { "E", "F" },
    { "G", "H" }
  }
};
for (int i = 0; i < 2; i++) {
  for (int j = 0; j < 2; j++) {
    for (int k = 0; k < 2; k++) {
      cout << letters[i][j][k] << "\n";
    }
  }
}

# 為什麼需要多維陣列?

多維陣列非常適合用來表示網格。以下範例展示一個實際應用:使用多維陣列來表示簡易版的戰艦(Battleship)遊戲:

// We put "1" to indicate there is a ship.
bool ships[4][4] = {
  { 0, 1, 1, 0 },
  { 0, 0, 0, 0 },
  { 0, 0, 1, 0 },
  { 0, 0, 1, 0 }
};
// Keep track of how many hits the player has and how many turns they have played in these variables
int hits = 0;
int numberOfTurns = 0;
// Allow the player to keep going until they have hit all four ships
while (hits < 4) {
  int row, column;
  cout << "Selecting coordinates\n";
  // Ask the player for a row
  cout << "Choose a row number between 0 and 3: ";
  cin >> row;
  // Ask the player for a column
  cout << "Choose a column number between 0 and 3: ";
  cin >> column;
  // Check if a ship exists in those coordinates
  if (ships[row][column]) {
    // If the player hit a ship, remove it by setting the value to zero.
    ships[row][column] = 0;
    // Increase the hit counter
    hits++;
    // Tell the player that they have hit a ship and how many ships are left
    cout << "Hit! " << (4-hits) << " left.\n\n";
  } else {
    // Tell the player that they missed
    cout << "Miss\n\n";
  }
  // Count how many turns the player has taken
  numberOfTurns++;
}
cout << "Victory!\n";
cout << "You won in " << numberOfTurns << " turns";

# C++ 結構(Structures /struct)

結構(structures,也稱為 structs)是一種把數個相關變數集合在一起的方法。

結構中的每個變數稱為結構的一個成員(member)。

與陣列不同,結構可以包含許多不同的資料型態: int 、 string 、 bool 等等。

# 建立結構

要建立結構,使用 struct 關鍵字,並在大括號內宣告每個成員。

宣告之後,指定結構變數的名稱(以下範例中的 myStructure):

struct { // Structure declaration
  int myNum; // Member (int variable)
  string myString; // Member (string variable)
} myStructure; // Structure variable

# 存取結構成員

要存取結構的成員,使用點語法( . ):

賦值給結構的成員並印出它:

// Create a structure variable called myStructure
struct {
  int myNum;
  string myString;
} myStructure;
// Assign values to members of myStructure
myStructure.myNum = 1;
myStructure.myString = "Hello World!";
// Print members of myStructure
cout << myStructure.myNum << "\n";
cout << myStructure.myString << "\n";

# 一個結構對應多個變數

可以使用逗號( , )讓一個結構套用到多個變數:

struct {
  int myNum;
  string myString;
} myStruct1, myStruct2, myStruct3; // Multiple structure variables separated with commas

以下範例展示如何在兩個不同的變數中使用同一個結構:

用一個結構表示兩台車:

struct {
  string brand;
  string model;
  int year;
} myCar1, myCar2; // We can add variables by separating them with a comma here
// Put data into the first structure
myCar1.brand = "BMW";
myCar1.model = "X5";
myCar1.year = 1999;
// Put data into the second structure
myCar2.brand = "Ford";
myCar2.model = "Mustang";
myCar2.year = 1969;
// Print the structure members
cout << myCar1.brand << " " << myCar1.model << " " << myCar1.year << "\n";
cout << myCar2.brand << " " << myCar2.model << " " << myCar2.year << "\n";

# 具名結構(Named Structures)

透過給結構命名,可以把它當作一種資料型態使用。這代表你可以在程式中的任何地方、任何時候,用這個結構建立變數。

要建立具名結構,把結構的名稱放在 struct 關鍵字後面:

struct car { // This structure is now named "car"
  string brand;
  string model;
  int year;
};

要宣告使用該結構的變數,就用結構的名稱作為變數的資料型態:

car myCar1;

現在這個結構可以在任何地方以 car 作為資料型態重複使用:

用一個結構表示兩台車:

// Declare a structure named "car"
struct car {
  string brand;
  string model;
  int year;
};
int main() {
  // Create a car structure and store it in myCar1;
  car myCar1;
  myCar1.brand = "BMW";
  myCar1.model = "X5";
  myCar1.year = 1999;
  // Create another car structure and store it in myCar2;
  car myCar2;
  myCar2.brand = "Ford";
  myCar2.model = "Mustang";
  myCar2.year = 1969;
  // Print the structure members
  cout << myCar1.brand << " " << myCar1.model << " " << myCar1.year << "\n";
  cout << myCar2.brand << " " << myCar2.model << " " << myCar2.year << "\n";
  return 0;
}

# 挑戰任務

建立一個結構來表示一位學生,應包含以下成員:

  • name ( string )
  • age ( int )
  • grade ( char )

接著:

  1. 建立一個該結構的變數。
  2. 賦值給它的成員。
  3. 將這些值印到螢幕上。

# 預期輸出

Name: Liam
Age: 35
Grade: A

# 解答範例

#include <iostream>
#include <string>
using namespace std;
struct student {
  string name;
  int age;
  char grade;
};
int main() {
  student s1;
  s1.name = "John";
  s1.age = 35;
  s1.grade = 'A';
  cout << "Name: " << s1.name << "\n";
  cout << "Age: " << s1.age << "\n";
  cout << "Grade: " << s1.grade << "\n";
  return 0;
}

# C++ 列舉(Enumeration /enum)

enum 是一種特殊型態,用來表示一組常數(不可變更的值)。

要建立 enum,使用 enum 關鍵字,接著是 enum 的名稱,並用逗號分隔各個項目:

enum Level {
  LOW,
  MEDIUM,
  HIGH
};

注意最後一項不需要加逗號。

不一定要用大寫,但這通常被視為較佳做法。

Enum 是 "enumerations" 的縮寫,意思是「明確列舉出來」。

要存取 enum,必須先建立一個該 enum 的變數。

在 main() 方法內,指定 enum 關鍵字,接著是 enum 的名稱( Level ),再接著是 enum 變數的名稱(本範例中的 myVar ):

enum Level myVar;

現在已經建立了一個 enum 變數( myVar ),可以賦值給它。

賦予的值必須是 enum 中的其中一個項目( LOW 、 MEDIUM 或 HIGH ):

enum Level myVar = MEDIUM;

預設情況下,第一個項目( LOW )的值是 0 ,第二個( MEDIUM )是 1 ,以此類推。

如果現在嘗試印出 myVar,會輸出 1 ,代表 MEDIUM :

int main() {
  // Create an enum variable and assign a value to it
  enum Level myVar = MEDIUM;
  // Print the enum variable
  cout << myVar;
  return 0;
}

# 改變數值

如你所知,enum 的第一個項目值為 0,第二個為 1,以此類推。

為了讓這些數值更有意義,可以輕鬆地改變它們:

enum Level {
  LOW = 25,
  MEDIUM = 50,
  HIGH = 75
};
int main() {
  enum Level myVar = MEDIUM;
  cout << myVar; // Now outputs 50
  return 0;
}

注意,如果為某一個項目指定了值,後面的項目也會依照該值往後遞增:

enum Level {
  LOW = 5,
  MEDIUM, // Now 6
  HIGH // Now 7
};

# 在 Switch 陳述式中使用 Enum

Enum 經常用在 switch 陳述式中,用來檢查對應的值:

enum Level {
  LOW = 1,
  MEDIUM,
  HIGH
};
int main() {
  enum Level myVar = MEDIUM;
  switch (myVar) {
    case 1:
      cout << "Low Level";
      break;
    case 2:
      cout << "Medium level";
      break;
    case 3:
      cout << "High level";
      break;
  }
  return 0;
}

# 為什麼、以及何時使用 Enum?

Enum 用來為常數賦予名稱,讓程式碼更容易閱讀與維護。

當你有一些確定不會改變的值時,就適合使用 enum,例如月份的天數、星期、顏色、一副撲克牌等等。

# C++ 參考(References)

# 建立參考

參考變數是既有變數的別名(alias),使用 & 運算子建立:

string food = "Pizza"; // food variable
string &meal = food; // reference to food

現在,可以用 food 或 meal 來指向同一個值:

string food = "Pizza";
string &meal = food;
cout << food << "\n"; // Outputs Pizza
cout << meal << "\n"; // Outputs Pizza

注意: food 與 meal 都指向同一個記憶體位置,修改其中一個也會影響另一個。

# 透過參考更新值

如果修改參考變數的值,原本的變數也會跟著改變(反之亦然),因為它們指向同一個記憶體位置:

string food = "Pizza"; // food variable
string &meal = food; // reference to food
meal = "Burger"; // changes both meal and food
cout << food << "\n"; // Outputs Burger
cout << meal << "\n"; // Outputs Burger

# C++ 記憶體位址(Memory Address)

在前一節的範例中, & 運算子被用來建立參考變數。但它也可以用來取得變數的記憶體位址,也就是該變數在電腦中儲存的位置。

在 C++ 中建立變數時,會為該變數分配一個記憶體位址。當我們賦值給該變數時,這個值就會被儲存在這個記憶體位址中。

要存取它,使用 & 運算子,結果會代表該變數儲存的位置:

string food = "Pizza";
cout << &food; // Outputs 0x6dfed4

注意: 記憶體位址是以十六進位形式(0x..)表示。你在自己的程式中得到的結果可能會不一樣。

# 為什麼要知道記憶體位址?

參考(References)與指標(Pointers)(下一節會學到)在 C++ 中很重要,因為它們讓你有能力直接操作電腦記憶體中的資料 —— 這能減少程式碼並提升效能。

這兩個特性是 C++ 與其他程式語言(如 Python 與 Java)與眾不同的地方之一。

# C++ 指標(Pointers)

# 建立指標

前一節學到,我們可以用 & 運算子取得一個變數的記憶體位址:

string food = "Pizza"; // A food variable of type string
cout << food; // Outputs the value of food (Pizza)
cout << &food; // Outputs the memory address of food (0x6dfed4)

而指標(pointer)則是一種把記憶體位址當作自己的值來儲存的變數。

指標變數指向一個相同型態的資料型態(如 int 或 string ),使用 * 運算子建立。你所操作的變數的位址會被賦值給這個指標:

string food = "Pizza"; // A food variable of type string
string* ptr = &food; // A pointer variable, with the name ptr, that stores the address of food
// Output the value of food (Pizza)
cout << food << "\n";
// Output the memory address of food (0x6dfed4)
cout << &food << "\n";
// Output the memory address of food with the pointer (0x6dfed4)
cout << ptr << "\n";

# 範例解說

建立一個名為 ptr 的指標變數,透過星號 * ( string* ptr )來指向一個 string 變數。注意,指標的型態必須與你所操作的變數型態相符。

使用 & 運算子取得名為 food 的變數的記憶體位址,並將它賦值給指標。

現在, ptr 儲存的就是 food 的記憶體位址。

小提示: 宣告指標變數有三種寫法,但第一種是較常用的寫法:

string* mystring; // Preferred
string *mystring;
string * mystring;

# 取值(Dereference)

前一節的範例中,我們使用指標變數搭配 & 參考運算子來取得變數的記憶體位址。不過,也可以使用指標搭配 * 運算子(取值(dereference)運算子)來取得變數的值:

string food = "Pizza"; // Variable declaration
string* ptr = &food; // Pointer declaration
// Reference: Output the memory address of food with the pointer (0x6dfed4)
cout << ptr << "\n";
// Dereference: Output the value of food with the pointer (Pizza)
cout << *ptr << "\n";

注意, * 符號在這裡可能會讓人混淆,因為它在程式碼中做了兩件不同的事:

  • 在宣告時使用( string* ptr ),它會建立一個指標變數。
  • 不在宣告時使用,則作為取值運算子。

# 修改指標的值

也可以修改指標的值,但要注意這也會改變原始變數的值:

string food = "Pizza";
string* ptr = &food;
// Output the value of food (Pizza)
cout << food << "\n";
// Output the memory address of food (0x6dfed4)
cout << &food << "\n";
// Access the memory address of food and output its value (Pizza)
cout << *ptr << "\n";
// Change the value of the pointer
*ptr = "Hamburger";
// Output the new value of the pointer (Hamburger)
cout << *ptr << "\n";
// Output the new value of the food variable (Hamburger)
cout << food << "\n";

# C++ 記憶體管理(Memory Management)

記憶體管理是控制程式使用多少記憶體、以及如何使用記憶體的過程。這包括在不再需要記憶體時,建立、使用與釋放記憶體。

# C++ 中的記憶體

當你在 C++ 中建立一個變數時,編譯器會自動為它保留記憶體空間。

例如:

int myNumber = 10;

上面這行告訴程式:「我需要空間來儲存一個整數。」C++ 會自動處理這個記憶體,所以在這種情況下,不需要擔心記憶體管理的問題。

# 取得記憶體大小

可以使用 sizeof 運算子,檢查某個變數型態使用了多少記憶體:

#include <iostream>
using namespace std;
int main() {
  int myInt;
  float myFloat;
  double myDouble;
  char myChar;
  cout << sizeof(myInt) << "\n"; // 4 bytes (typically)
  cout << sizeof(myFloat) << "\n"; // 4 bytes
  cout << sizeof(myDouble) << "\n"; // 8 bytes
  cout << sizeof(myChar) << "\n"; // 1 byte
  return 0;
}

了解各型態的大小有助於寫出更有效率的程式碼,尤其是在較大型的程式中。

# 需要自己管理記憶體嗎?

有時候需要,有時候不需要。

  • 對於一般的變數(如 int x = 10; ),C++ 會自動幫你處理記憶體。
  • 但當你想在程式執行期間手動建立記憶體時(例如根據使用者輸入),就需要自己管理,並在用完之後自行清理。

如果程式使用了過多的記憶體,或忘記清理不再需要的記憶體,可能會導致效能變慢,甚至當機。

這就是為什麼理解記憶體很重要,它能讓你有更多的控制權,並幫助避免常見的錯誤。

# 接下來呢?

在 C++ 中,可以使用指標直接存取與修改記憶體。

這個功能很強大,但也有風險。如果指標使用不當,可能會意外修改或破壞程式其他部分的記憶體。

下一節會學到如何使用指標,搭配 new 關鍵字手動建立記憶體,並使用 delete 來釋放它。

# C++ new 與 delete

# new 關鍵字

new 關鍵字讓你可以自己管理記憶體。

以下範例中,我們使用 new 為一個整數建立記憶體空間,將值 35 存進去,並使用指標印出它:

int* ptr = new int;
*ptr = 35;
cout << *ptr;

說明:

  • new int 為一個整數建立記憶體空間
  • ptr 儲存該空間的位址
  • *ptr = 35; 儲存數字 35
  • cout << *ptr; 印出這個值

所以我們用 new 來建立記憶體,用 ptr 來存取它。

# delete 關鍵字

當你用 new 建立了東西之後,用完之後要負責把它移除。

要做到這件事,使用 delete :

delete ptr;

這會告訴 C++:「我已經用完這塊記憶體了,你現在可以清理它了。」

# 如果忘記 delete 會怎樣?

如果忘記刪除記憶體,程式仍然可以執行,但隨著時間過去,它可能會使用越來越多的記憶體。

這稱為記憶體洩漏(memory leak),長期下來可能會讓程式變慢,甚至當機。

# 對陣列使用 new 與 delete

也可以使用 new 關鍵字來建立動態陣列。

注意: 對於陣列,要使用 new[] 與 delete[] ;對於單一變數,則使用 new 與 delete 。

當你事先不知道陣列的大小時,動態陣列就很有用 —— 例如陣列的大小取決於使用者輸入,或是程式一開始還不知道的其他數值。

舉例來說,假設你經營一間旅館。因為不知道會有多少位客人到來,所以你詢問使用者人數,並依照這個數字建立相對應數量的房間 —— 每個房間用來儲存一位客人的名字:

#include <iostream>
#include <string>
using namespace std;
int main() {
  int numGuests;
  cout << "How many guests? ";
  cin >> numGuests;
  // Check for invalid input
  if (numGuests <= 0) {
    cout << "Number of guests must be at least 1.\n";
    return 0;
  }
  // Create memory space for x guests (an array of strings)
  string* guests = new string[numGuests];
  // Ignore the leftover newline character after reading numGuests
  cin.ignore();
  // Enter guest names
  for (int i = 0; i < numGuests; i++) {
    cout << "Enter name for guest " << (i + 1) << ": ";
    getline(cin, guests[i]); // Read the full name (including spaces)
  }
  // Show all guests
  cout << "\nGuests checked in:\n";
  for (int i = 0; i < numGuests; i++) {
    cout << guests[i] << "\n";
  }
  delete[] guests; // Clean up memory
  return 0;
}

# 何時使用 new

大多數情況下,不需要使用 new 。對於一般變數,C++ 會自動處理記憶體,例如:

int age = 35;
string name = "John";

但有時候,你必須自己管理記憶體,尤其是在以下情況:

  • 事先不知道需要多少記憶體(例如有多少位客人或分數)
  • 想在程式執行期間,根據使用者輸入來建立記憶體
  • 需要儲存大量或彈性大小的資料
  • 想要完全手動控制記憶體(例如效能要求高的程式碼)

在這些情況下, new 可以幫你建立記憶體,而 delete 可以幫你在用完之後清理它。

小提示: 如果使用了 new ,務必記得使用 delete (陣列則用 delete[] ),以避免記憶體洩漏。

# C++ 函式(Functions)

函式是一段程式碼區塊,只有在被呼叫時才會執行。

你可以把資料(稱為參數,parameters)傳入函式。

函式用來執行特定的動作,對於重複使用程式碼來說非常重要:定義一次程式碼,就可以多次使用。

# 建立函式

C++ 提供了一些預先定義好的函式,例如用來執行程式碼的 main() 。但你也可以建立自己的函式來執行特定的動作。

要建立(常稱為_宣告_)一個函式,需指定函式的名稱,後面加上括號 ():

語法:

void myFunction() {
  // code to be executed
}

# 範例解說

  • myFunction() 是函式的名稱
  • void 代表這個函式沒有回傳值,下一節會詳細說明回傳值
  • 在函式內部(函式主體)加入定義該函式該做什麼的程式碼

# 呼叫函式

宣告好的函式不會立刻執行。它們會被「儲存起來以供之後使用」,等到被呼叫時才會執行。

要呼叫函式,寫出函式名稱,後面加上一對括號 () 與分號 ;

以下範例中, myFunction() 在被呼叫時用來印出一段文字(這個動作):

在 main 中呼叫 myFunction() :

// Create a function
void myFunction() {
  cout << "I just got executed!";
}
int main() {
  myFunction(); // call the function
  return 0;
}
// Outputs "I just got executed!"

一個函式可以被呼叫多次:

void myFunction() {
  cout << "I just got executed!\n";
}
int main() {
  myFunction();
  myFunction();
  myFunction();
  return 0;
}
// I just got executed!
// I just got executed!
// I just got executed!

# 函式的宣告與定義

C++ 的函式由兩個部分組成:

  • 宣告(Declaration): 回傳型態、函式名稱,以及參數(如果有的話)
  • 定義(Definition): 函式的主體(要執行的程式碼)
void myFunction() { // declaration
  // the body of the function (definition)
}

注意: 如果像 myFunction() 這樣的自訂函式,宣告的位置在 main() 函式之後,就會發生錯誤:

int main() {
  myFunction();
  return 0;
}
void myFunction() {
  cout << "I just got executed!";
}
// Error

不過,為了讓程式碼優化,是可以把函式的宣告與定義分開的。

你經常會看到 C++ 程式把函式宣告放在 main() 的上方,而函式定義放在 main() 的下方,這樣可以讓程式碼組織得更好、更容易閱讀:

// Function declaration
void myFunction();
// The main method
int main() {
  myFunction(); // call the function
  return 0;
}
// Function definition
void myFunction() {
  cout << "I just got executed!";
}

# C++ 函式參數(Function Parameters)

# 參數與引數(Parameters and Arguments)

可以把資訊以參數的形式傳遞給函式。參數在函式內部的作用就像變數一樣。

參數寫在函式名稱後面的括號內。可以加入任意數量的參數,只需用逗號分隔:

語法:

void functionName(parameter1, parameter2, parameter3) {
  // code to be executed
}

以下範例的函式接收一個名為 fname 的 string 參數。呼叫函式時,我們傳入一個名字,函式內部會用它來印出全名:

void myFunction(string fname) {
  cout << fname << " Refsnes\n";
}
int main() {
  myFunction("Liam");
  myFunction("Jenny");
  myFunction("Anja");
  return 0;
}
// Liam Refsnes
// Jenny Refsnes
// Anja Refsnes

當一個參數(parameter)被傳遞給函式時,它被稱為一個引數(argument)。所以在上面的範例中: fname 是參數,而 Liam 、 Jenny 與 Anja 則是引數。

更新於 閱讀次數 次