C / C++ 函式傳遞二維陣列 範例與解說
一維陣列的傳遞
一維陣列常見的方法是這樣傳遞的
void fun(int* p){...}
int arr[10]={};
fun(arr);
這時候編譯器會自動將 型態::int[10]
轉成 型態::int*
然後成功的傳遞
但是這裡有個但書,只有最高維度可以自動轉換或計算,剩下的皆要手動指定
舉個例子來說明
// 錯誤
int arr[][] = {{0,1},{2,3}};
// 正確
int arr[][2] = {{0,1},{2,3}};
編譯器只會自動補上 最左邊的[] ,只有最左邊可以留空
在函式上二維的傳遞方式也是一樣的邏輯,想傳遞這個二維可以改成這樣
// 寫法1
void fun(int p[][2]){...}
// 寫法2 (等價於第一種,看個人習慣選擇即可)
void fun(int (*p)[2]){...}
這樣就可以正常傳遞了,只是有個缺點二維的長度被限制了。
不定長度的二維傳遞 - 手動轉型
那如果要傳遞不定長的二維就必須使用指標的指標 int**
來傳遞
不過這樣的用法沒辦法直接從int(*)[n]
轉型,必須手動轉型
如果想要自動轉型成 int**
反推一下就要使用 int*
的陣列來轉型
int
的陣列是一個陣列裡面放著一堆int
int*
的陣列是一個陣列裡面放著一堆int*
就是說二維陣列,可以想像成有一個一維陣列
裡面放著一堆一維陣列
// 宣告二維陣列
int arr1[2][2] = {{1,2},{3,4}};
// 取出一維陣列位址
int* a1 = arr1[0];
int* a2 = arr1[1];
// 把一維地址寫進陣列裡
int* p1[2];
p1[0] = a1;
p1[1] = a2;
現在p1可以自動轉型成 int**
了,可以將它傳入了 int**
的函式內了
會弄得這麼麻煩是因為維度的長度
,本身就屬於型態的一部分。陣列長度10跟陣列長度11的差別就好像 int 跟 char 的差別一樣完全是不一樣的東西
而編譯器只會幫你處理最高維度的自動計算而已,所以二維以上不定長度的傳遞在C語言上比較棘手。C++的話有樣板可以自動處理就沒這個困擾了。
範例
/*****************************************************************************
Name :
Date : 2018/06/13
By : CharlotteHonG
Final: 2018/06/13
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define WIDTH 2
#define HEIGHT 3
void fun(int** p) {
for (int j = 0; j < HEIGHT; ++j) {
for (int i = 0; i < WIDTH; ++i) {
printf("%d, ", p[j][i]);
} printf("\n");
}
}
int main(int argc, char **argv) {
int arr[HEIGHT][WIDTH] = {};
int* p[HEIGHT];
for (int j = 0; j < HEIGHT; ++j) {
p[j] = arr[j];
for (int i = 0; i < WIDTH; ++i) {
arr[j][i] = 1;
}
}
fun(p);
return 0;
}
如何傳遞陣列的長寬
這是轉成指標之後的缺點,他將會遺失陣列的長度資訊,常見辦法
- 讓函式多一個參數傳入
- 用陣列的第一個數值來當作長度
C++的樣板可以解決這個問題,寫法如下
template<size_t N, size_t N2>
void fun(int (&arr)[N][N2]) {...};
如此一來就可以完整的傳入鎮列了,在函式內 N1 及 N2 就是傳入的二維長度,一維或是三維以上只要調整N的數量對應即可。
沒有留言:
張貼留言