# C++ 呼叫自訂函式修改二維 array 及 vector
> 作者:王一哲
> 日期:2023年10月6日
## 前言
由於 Python 的自訂函式可以回傳 list,如果要呼叫自訂函式修改 list 的內容相當簡單,只要將 list 的內容重設為回傳值即可,例如以下的程式碼:
```python=
# 修改1維 list
def myfunc(a):
a[2] = -1
return a
def myprint(a):
for i in range(len(a)):
print(a[i], end=" " if i < len(a)-1 else "\n")
data = [1]*5 # 內容為 [1, 1, 1, 1, 1]
print("1D List")
myprint(data)
print("Modify 1D List")
data = myfunc(data) # 內容變為 [1, 1, -1, 1, 1]
myprint(data)
```
<br />
```python=
# 修改2維 list
def myfunc(a):
a[2][2] = -1
return a
def myprint(a):
for i in range(len(a)):
for j in range(len(a[i])):
print(a[i][j], end=" " if j < len(a[i])-1 else "\n")
data = [[1]*5 for _ in range(3)] # 內容為 [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]
print("2D List")
myprint(data)
print("Modify 2D List")
data = myfunc(data) # 內容變為 [[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, -1, 1, 1]]
myprint(data)
```
<br /><br />
但是 C++ 呼叫自訂函式時,無法回傳 array 或 vector,如果要使用自訂函式修改 array 或 vector 的內容,需要使用**傳指標呼叫 (\*)** 或是**傳參考呼叫 (&)**,以下是簡單的例子。
<br /><br />
## 修改 array
### 1維 array
建立 array 時需要使用指標,再用 new 分配記憶體給 array,最後用 for 迴圈設定 array 的內容。呼叫自訂函式修改 array 內容時,要使用傳指標呼叫,不需要回傳值。
```cpp=
#include <iostream>
using namespace std;
void myfunc(int*);
void myprint(int*, int);
int main() {
int n = 5;
int *data; // 不能直接使用 int data[n]
data = new int [n];
for(int i=0; i<n; i++) data[i] = 1; // 內容為 {1, 1, 1, 1, 1}
cout << "1D Array" << endl;
myprint(data, n);
cout << "Modify 1D Array" << endl;
myfunc(data); // 內容變為 {1, 1, -1, 1, 1}
myprint(data, n);
return 0;
}
/* 自訂函式,呼叫後將索引值為2的元素改為-1 */
void myfunc(int *a) {
a[2] = -1;
}
/* 自訂函式,印出 array 內容,用空格分隔,印出最後一個元素時換行 */
void myprint(int *a, int n) {
for(int i=0; i<n; i++) {
cout << a[i] << " \n"[i == n-1];
}
}
```
<br />
編譯後執行時輸出
```cpp
1D Array
1 1 1 1 1
Modify 1D Array
1 1 -1 1 1
```
<br /><br />
### 2維 array
建立 2維 array 時需要使用雙重指標,再用 new 分配記憶體給 array,最後用 for 迴圈設定 array 的內容。呼叫自訂函式修改 array 內容時,要使用傳指標呼叫,不需要回傳值。
```cpp=
#include <iostream>
using namespace std;
void myfunc(int**);
void myprint(int**, int, int);
int main() {
int n = 3, m = 5;
int **data; // 不能直接使用 int data[n][m]
data = new int *[n]; // n 個指標物件,1維 array
// 使用2層 for 迴圈填入元素值,data 內容為 {{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}}
for(int i=0; i<n; i++) {
data[i] = new int [m]; // m 個元素的1維 array
for(int j=0; j<m; j++) {
data[i][j] = 1;
}
}
cout << "2D Array" << endl;
myprint(data, n, m);
cout << "Modify 2D Array" << endl;
myfunc(data); // 內容變為 {{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, -1, 1, 1}}
myprint(data, n, m);
return 0;
}
/* 自訂函式,呼叫後將索引值為[2][2]的元素改為-1 */
void myfunc(int **a) {
a[2][2] = -1;
}
/* 自訂函式,印出 array 內容,用空格分隔,印出每列最後一個元素時換行 */
void myprint(int **a, int n, int m) {
for(int i=0; i<n; i++) {
for(int j=0; j<m; j++) {
cout << a[i][j] << " \n"[j == m-1];
}
}
}
```
<br />
編譯後執行時輸出
```cpp
2D Array
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
Modify 2D Array
1 1 1 1 1
1 1 1 1 1
1 1 -1 1 1
```
<br /><br />
## 修改 vector
### 1維 vector
依照一般的方式建立 vector 即可,呼叫自訂函式修改 vector 內容時,要使用傳參考呼叫,不需要回傳值。
```cpp=
#include <iostream>
#include <vector>
using namespace std;
void myfunc(vector<int>&);
void myprint(vector<int>);
int main() {
int n = 5;
vector<int> data (n, 1); // 內容為 {1, 1, 1, 1, 1}
cout << "1D Vector" << endl;
myprint(data);
cout << "Modify 1D Vector" << endl;
myfunc(data); // 內容變為 {1, 1, -1, 1, 1}
myprint(data);
return 0;
}
/* 自訂函式,呼叫後將索引值為2的元素改為-1 */
void myfunc(vector<int> &a) {
a[2] = -1;
}
/* 自訂函式,印出 vector 內容,用空格分隔,印出最後一個元素時換行 */
void myprint(vector<int> a) {
for(auto it = a.begin(); it != a.end(); it++) {
cout << *it << " \n"[it == a.end()-1];
}
}
```
<br />
編譯後執行時輸出
```cpp
1D Vector
1 1 1 1 1
Modify 1D Vector
1 1 -1 1 1
```
<br /><br />
### 2維 vector
依照一般的方式建立 vector 即可,呼叫自訂函式修改 vector 內容時,要使用傳參考呼叫,不需要回傳值。
```cpp=
#include <iostream>
#include <vector>
using namespace std;
void myfunc(vector<vector<int>>&);
void myprint(vector<vector<int>>);
int main() {
int n = 3, m = 5;
vector<vector<int>> data; // 建立空的2維 vector
// 使用 for 迴圈及 push_back 填入元素值,data 內容為 {{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}}
for(int i=0; i<n; i++) data.push_back(vector<int> (m, 1));
cout << "2D Vector" << endl;
myprint(data);
cout << "Modify 2D Vector" << endl;
myfunc(data); // 內容變為 {{1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, -1, 1, 1}}
myprint(data);
return 0;
}
/* 自訂函式,呼叫後將索引值為[2][2]的元素改為-1 */
void myfunc(vector<vector<int>> &a) {
a[2][2] = -1;
}
/* 自訂函式,印出 vector 內容,用空格分隔,印出每列最後一個元素時換行 */
void myprint(vector<vector<int>> a) {
for(auto it = a.begin(); it != a.end(); it++) {
for(auto it2 = (*it).begin(); it2 != (*it).end(); it2++) {
cout << *it2 << " \n"[it2 == (*it).end()-1];
}
}
}
```
<br />
編譯後執行時輸出
```cpp
2D Vector
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
Modify 2D Vector
1 1 1 1 1
1 1 1 1 1
1 1 -1 1 1
```
<br /><br />
## 結語
以上的技巧在 APCS 實作題中偶爾會用到,例如111年10月APCS實作題第2題[運貨站](https://hackmd.io/@yizhewang/SJeigpwga),我使用2維 array 儲存倉庫格子的資料,呼叫自訂函式檢查貨物是否能放入倉庫,如果可以放入倉庫則修改對應的格子狀態,需要透過自訂函式修改2維 array 的內容。希望這篇筆記能幫助到有需要的同學。
<br /><br />
---
###### tags:`C++`、`Python`