Semorphe

vector

一排東西,而且長度可以變。 · ⏱ 約 30 分鐘

你會學到三件事

  1. vector 是長度會變的陣列
  2. push_back 往後面加、size() 問現在幾個
  3. 範圍 for:不管位置,只要每一個

開始之前

第 13 課的陣列有一個硬限制:格數在寫程式的時候就要決定。

int n;
cin >> n;
int a[n];     // ⚠️ 標準 C++ 不允許

而「要幾格」常常要等程式跑起來才知道。vector 解決這件事。

🟢 先把編輯器打開,跟著下面一起做:跟著做

一、一開始是空的

vector 不用先說幾格:

1vector<int> v;
建立int(整數)列表v大小每格填複製自使用命名空間std引入函式庫vector(動態列表)1
這一段 意思
vector 一排會變長的東西
<int> 裡面每一格裝整數
v 名字

⚠️ 沒有 [5]:它一開始是空的,一格都沒有。

積木盤上這一顆寫著「建立 … 列表 …」。

那個角括號 <int> 是新的寫法。它的意思是「這個 vector 是裝 int 的」。 換成 vector<string> 就是裝字串的。

二、往後面加

要多一個就往後面加:

1v.push_back(3);2v.push_back(1);3v.push_back(4);4cout << v.size() << endl;    // 3
3變數v1變數v4變數v變數v的長度換行0回傳印出在尾端加入在尾端加入在尾端加入定義函式 回傳型別int(整數)main使用命名空間std引入函式庫vector(動態列表)引入函式庫iostream(輸入輸出)1234

又是第 14 課那個「點」的寫法,唸成「的」:v.size() 就是「v 的 size」。 點的左邊是誰,右邊是問它什麼、叫它做什麼。

寫法 做什麼
v.push_back(x) 在最後面加一個 x,長度加一(積木上:「在 … 尾端加入 …」)
v.size() 現在有幾個
v.back() 最後一個是什麼
v.pop_back() 把最後一個丟掉,長度減一

⚠️ v.pop_back() 不會把那個值還給你,它只是丟掉。 要先 v.back() 拿到再 pop_back()。

三、拿第幾個

和陣列一模一樣:

🔎 這一段是試一下——打了看結果就好,不要留在程式裡。

1cout << v[0] << endl;    // 3
變數v0陣列的第 [] 格換行0回傳印出定義函式 回傳型別int(整數)main使用命名空間std引入函式庫iostream(輸入輸出)1

位置一樣從 0 開始,v[v.size()] 一樣不存在。 ⚠️ vector 也不會攔你越界,它跟陣列一樣危險。

四、範圍 for

想走過每一個而不在乎位置的時候,有更短的寫法:

1for (int x : v) {2    cout << x << endl;3}
變數v變數(自訂)換行印出對每個intx在中使用命名空間std引入函式庫iostream(輸入輸出)12

讀法:「對 v 裡面的每一個 x,做這件事。」

積木盤上這一顆就寫著「對每個 …」——它的名字就是它的讀法。

它和 for (int i = 0; i < v.size(); i++) 走的是同一批東西。 把兩支並排看,差別只有一個地方:

1for (int i = 0; i < v.size(); i++) {2    cout << v[i] << endl;      // ← 要用 v[i] 才拿得到值3}
0變數v的長度變數v變數i陣列的第 [] 格換行印出計數i從到(不含)重複使用命名空間std引入函式庫vector(動態列表)引入函式庫iostream(輸入輸出)12
1for (int x : v) {2    cout << x << endl;         // ← x 本身就是那個值3}
變數v變數(自訂)換行印出對每個intx在中使用命名空間std引入函式庫iostream(輸入輸出)12

🔴 這是最容易搞混的一件事:

i  是【位置】     0, 1, 2, 3 ...     要拿值得寫 v[i]
x  是【值】       90, 85, 72 ...     它就是值,不用再查一次

⚠️ 所以 for (int x : v) cout << v[x]; 是錯的:那變成「拿第 90 個」, 而 v 根本沒有第 90 個。而它不會報錯,只會印出一個莫名其妙的數字。

換個角度想:i 是座位號碼,x 是坐在那個位子上的人。 用座位號碼要先去查是誰;拿到人就直接是人了。

拿得到位置 適合什麼
for (int i = 0; ...) ✅ 要知道「這是第幾個」
for (int x : v) ❌ 只要每一個值——不會寫錯邊界

不需要位置的時候用範圍 for。 少一個地方會寫錯,就是少一個 bug。

完成的樣子

這一課的參考做法——程式碼每一行的號碼,就印在對應的那塊積木上。

1#include <iostream>2#include <vector>3using namespace std;4int main() {5    vector<int> v;6    v.push_back(3);7    v.push_back(1);8    v.push_back(4);9    cout << v.size() << endl;10    for (int x : v) {11        cout << x << endl;12    }13    return 0;14}
3變數v1變數v4變數v變數v的長度換行變數v變數x換行印出0回傳對每個intx在中印出在尾端加入在尾端加入在尾端加入建立int(整數)列表v大小每格填複製自定義函式 回傳型別int(整數)main使用命名空間std引入函式庫vector(動態列表)引入函式庫iostream(輸入輸出)123456789101113

把積木打散,自己排回去:排回去:把剛才那支程式的積木排好

換你了

改成讀進使用者輸入的數字,直到輸入 0 為止,然後印出總共幾個。

提示:while (true) + 讀一個 + if (x == 0) break; + push_back。

到編輯器做這一題:練習:讀到 0 為止,印出總共幾個

做一個

讀進一串數字,讀到 0 為止。印出平均(整數除法),再印出高於平均的有幾個。

🔴 這一題非得走兩趟不可:第一趟不知道平均是多少,所以算不出第二個答案。 先試著用一趟做做看,卡住的地方就是這一題要教的東西。 ⚠️ 裁判用的是 10 20 30 40 0。

到編輯器做這一題:做一個:有幾個人高於平均

這一課你做了什麼

如果卡住了

你看到 多半是因為
vector 說沒宣告 目標不是 C++(C 沒有 vector)——看一下右下角
v[0] 拿到怪東西 vector 一開始是空的。要先 push_back
範圍 for 改了值卻沒生效 for (int x : v) 的 x 是複本。要改要寫 for (int& x : v)
範圍 for 印出一堆怪數字 寫成 v[x] 了。x 已經是值,不是位置
size() 比預期少一 pop_back() 多做了一次
在編輯器打開這一課 →