2 に答える
関数に配列を渡すのは、C および C++ では少しおかしいです。配列型の右辺値がないため、実際にはポインターを渡しています。
2D 配列 (配列の配列ではなく、実際の配列) をアドレス指定するには、データの 2 つのチャンクを渡す必要があります。
- 開始位置へのポインタ
- 1行の幅
そして、これらは、C か C++ か、VLA を使用するか、または使用しないかなど、2 つの別個の値です。
それを書くいくつかの方法:
最もシンプルで、どこでも機能しますが、より多くの手作業が必要です
void foo(int width, int* arr) {
arr[x + y*width] = 5;
}
VLA、標準 C99
void foo(int width, int arr[][width]) {
arr[x][y] = 5;
}
引数を逆にした VLA、前方パラメータ宣言 (GNU C 拡張)
void foo(int width; int arr[][width], int width) {
arr[x][y]=5;
}
C++ w/ VLA (GNU C++ 拡張機能、ひどく醜い)
void foo(int width, int* ptr) {
typedef int arrtype[][width];
arrtype& arr = *reinterpret_cast<arrtype*>(ptr);
arr[x][y]=5;
}
大きな発言:
2D 配列の [x][y] 表記は、配列の型に幅が含まれているため機能します。VLA なし = コンパイル時に配列型を修正する必要があります。
したがって、VLAを使用できない場合は...
- Cでそれを処理する方法はありません。
- C ++でオーバーロードされた演算子のオーバーロードを伴うプロキシクラスなしでは、それを処理する方法はありません。
VLA (C99 または GNU C++ 拡張機能) を使用できる場合は...
- あなたはCのグリーンにいます、
- C++ ではまだ混乱が必要です。代わりにクラスを使用してください。
C++ の場合boost::multi_array
は、堅実な選択です。
回避策
2D 配列の場合、2 つの別々の割り当てを行うことができます。
T
(A)へのポインタの 1D 配列T
(B)の 2D 配列
次に、(A) のポインターを (B) のそれぞれの行を指すように設定します。
このセットアップでは、単純に (A) を渡すだけで、インデックス作成T**
で適切に動作します。[x][y]
この解決策は 2D には適していますが、より高い次元ではますますボイラープレートが必要になります。また、間接レイヤーが余分にあるため、VLA ソリューションよりも遅くなります。
B
すべての行に個別の割り当てを行う同様のソリューションに遭遇することもあります。C では、これは malloc-in-a-loop のように見え、C++ の vector-of-vectors に似ています。ただし、これにより、配列全体を 1 つのブロックに含める利点が失われます。
これを行うための明確な方法はありませんが、回避策を使用して 2 次元配列を 1 次元配列として扱い、関数内で 2 次元配列に再変換することができます。
void foo2(int n, int *arr)
{
int *ptr; // use this as a marker to go to next block
int i;
int j;
for(i = 0; i < n; i++)
{
ptr = arr + i*n; // this is the starting for arr[i] ...
for (j = 0; j < n ;j++)
{
printf(" %d ", ptr[j]); // This is same as arr[i][j]
}
}
}
void bar2()
{
int arr[10][10];
foo2(10, (int *)arr);
}