42
4

2 に答える 2

56

関数に配列を渡すのは、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 つのブロックに含める利点が失われます。

于 2013-01-27T15:45:55.077 に答える
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);
}
于 2016-11-28T00:23:31.170 に答える