2

CまたはC++でサイズが不明な多次元配列を参照で渡す方法は?

編集:

たとえば、main関数には次のものがあります。

int main(){
    int x, y;
    int arr[x][y];
    // pass_by_ref(/* passing just arr[][] by reference */);
}  

および機能:

void pass_by_ref(/* proper parameter for arr[][] */){
    // int size_x_Arr = ???
    // int size_y_arr = ???
}

コメント行を実装する方法は?

4

5 に答える 5

4

簡単に言えば、できません。Cでは、Cには参照がないため、参照を渡すことはできません。C ++では、可変長配列をサポートしていないため、サイズが不明な配列を渡すことはできません。

代替ソリューション:C99では、可変長配列へのポインターを渡します。C ++では、への参照を渡しますstd::vector<std::vector<T>>

C99のデモンストレーション:

#include <stdio.h>

void foo(int n, int k, int (*arr)[n][k])
{
    int i, j;
    for (i = 0; i < n; i++) {
        for (j = 0; j < k; j++) {
            printf("%3d ", (*arr)[i][j]);
        }
        printf("\n");
    }
}

int main(int argc, char *argv[])
{
    int a = strtol(argv[1], NULL, 10);
    int b = strtol(argv[2], NULL, 10);

    int arr[a][b];
    int i, j;
    for (i = 0; i < a; i++) {
        for (j = 0; j < b; j++) {
            arr[i][j] = i * j;
        }
    }

    foo(a, b, &arr);

    return 0;
}

C ++ 03のデモンストレーション:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

void foo(std::vector < std::vector < int > > &vec)
{
    for (std::vector < std::vector < int > >::iterator i = vec.begin(); i != vec.end(); i++) {
        for (std::vector<int>::iterator j = i->begin(); j != i->end(); j++) {
            std::cout << *j << " ";
        }
        std::cout << std::endl;
    }
}

int main(int argc, char *argv[])
{
    int i = strtol(argv[1], NULL, 10);
    int j = strtol(argv[2], NULL, 10);

    srand(time(NULL));

    std::vector < std::vector < int > > vec;
    vec.resize(i);
    for (std::vector < std::vector < int > >::iterator it = vec.begin(); it != vec.end(); it++) {
        it->resize(j);
        for (std::vector<int>::iterator jt = it->begin(); jt != it->end(); jt++) {
            *jt = random() % 10;
        }
    }

    foo(vec);

    return 0;
}
于 2013-03-06T11:00:15.410 に答える
3

H2CO3のソリューションは、VLAをサポートするC99またはC2011コンパイラで機能します。VLAをサポートしないC89またはC2011コンパイラ、または(神は禁じられています)K&R Cコンパイラの場合、別のことをする必要があります。

連続して割り当てられた配列を渡すと仮定すると、最初の要素&a[0][0])へのポインターを次元サイズとともに渡し、それを1次元配列として扱い、インデックスを次のようにマッピングできます。

void foo( int *a, size_t rows, size_t cols )
{
  size_t i, j;

  for (i = 0; i < rows; i++)
  {
    for (j = 0; j < cols; j++)
    {
      a[i * rows + j] = some_value();
    }
  }
}

int main( void )
{
  int arr[10][20];

  foo( &arr[0][0], 10, 20 );
  ...
  return 0;
}

これは、スタックに割り当てられたアレイで機能します。

T a[M][N];

および次の形式の動的に割り当てられた配列の場合:

T (*ap)[N] = malloc( M * sizeof *ap );

両方に連続して行が割り当てられるためです。これは、動的に割り当てられた次の形式の配列では機能しません(または、少なくとも機能が保証されません)。

T **ap = malloc( M * sizeof *ap );
if (ap)
{
  size_t i;
  for (i = 0; i < M; i++)
  {
    ap[i] = malloc( N * sizeof *ap[i] );
  }
}

すべての行が互いに連続して割り当てられることが保証されていないためです。

于 2013-03-06T11:58:41.980 に答える
0

これは@JohnBodeの良い答えに対する一種のコメントです

これは、動的に割り当てられた次の形式の配列では機能しません(または、少なくとも機能が保証されません)。

しかし、このバリアントは次のようになります。

T **ap = malloc( M * sizeof *ap );
if (ap) return NULL;     ---> some error atention
if (ap)
{
  ap[0] = malloc( M * N * sizeof *ap[i] );
  if (ap[0]) { free(ap); return NULL;}     ---> some error atention
  size_t i;
  for (i = 1; i < M; i++)
  {
    ap[i] = ap[0] + i * N;
  }
}

使用後:

free(ap[0]);
free(ap);

配列に対して正確Tにalsをint呼び出すためfooint ap[M][N];

  foo( &ap[0][0], M, N);

すべての行が互いに連続して割り当てられることを保証したためです。この割り当ては、より効率的です。

于 2013-03-06T13:20:54.803 に答える
0

John Bodeの説明は非常に優れていますが、少し間違いがあります。

i * cols + j

それ以外の

i * rows + j
于 2014-01-24T18:49:41.583 に答える
-1

本当に参照が必要な場合は、C++のみです。

参照によって渡される2次元int配列の例

void function_taking_an_array(int**& multi_dim_array);

ただし、参照には利点がないため、次を使用してください。

void function_taking_an_array(int** multi_dim_array);

配列を保持するためにコンテナを使用することをお勧めします。

于 2013-03-06T10:55:44.513 に答える