1

一定サイズの配列の場合:

const int m = 5, n = 3;
int arr[m][n];

C89 と C++ の両方と互換性のある方法で関数に渡されますか?

void func(const int m, const int n, int arr[][n]) { }

arr のサイズはコンパイル時に決定されますが、有効な C++ ではありません (「パラメーターは許可されていません」や「変数 'n' はこのスコープで宣言されていません」などのエラーが発生します)。(ただし、これは有効な C です。) #define動作mnますが、スコープの問題により推奨されません。配列の最初の要素へのポインターを渡すと、関数本体のコードが見苦しくなります。

コンテキストについては、この FAQを参照してください。

4

5 に答える 5

2

私はこのコードを試しました:

void func(const int m, const int n, int arr[][n])
{
  printf("%d\n", arr[4][2]);
}

int             main()
{
 const int m = 5, n = 3;
 int arr[m][n];

 arr[4][2] = 10;
 func(m, n, arr);
}

これは警告なしで機能します

于 2013-07-16T23:56:51.113 に答える
0

ここでの問題は、C++ での動的配列の「欠落」サポートです。

const int m = 5, n = 3;
int arr[m][n];

m と n はコンパイル時定数であり、配列の宣言で直接アクセスできるため、機能します。

void func(const int m, const int n, int arr[][n]) { }

コンパイラは、最初に呼び出された場所に関係なく、関数を処理します。したがってn、未知/変数であるため、配列の次元として禁止されています。

次の例も、まったく同じ理由で機能しません。

void foo (const int n)
{
  int arr[n]; // error, n is const but not compile time constant
}

int main (void) 
{ 
  foo(4);
}

jxh はそれについて何をすべきかを答えました。

于 2013-07-17T00:30:14.290 に答える
0

ポインターアドレスを渡すことができるように、配列を動的に割り当てることを検討することをお勧めします。

const int m = 5, n = 3;
int i = 0;
int* *arr; //Pointer to an integer pointer (Note can also be int **arr or int** arr)

arr = malloc(sizeof(int*)*(m+1)); //I add one because I am assuming that 'm' does not account for the terminating null character. But if you do not need a terminating null then you can remove this and the perantheses around the 'm'.

for(i = 0; i < m; i++)
{
    arr[i] = malloc(sizeof(int*)*(n+1)); //Same as before
}

最初の malloc() 呼び出しは、整数配列の配列にメモリを割り当てます。別の言い方をすれば、一連の他のポインターにポインターを割り当てます。for ループは、元の配列の各要素にサイズ 'm' の整数配列を割り当てます。つまり、元のポインター アドレスが指すすべてのポインター アドレスにスペースを割り当てます。例を単純化するためにエラー チェックを省略しましたが、エラー チェックを含む同じ例を次に示します。

const int m = 5, n = 3;
int i = 0;
int* *arr = NULL;

if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
{
   perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
   return 1;
}

for(i = 0; i < m; i++)
{
   if((arr = malloc(sizeof(int*)*(m+1))) == NULL)
   {
      perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
      return 2;
   }
}

配列を動的に割り当てたので、ポインターアドレスを渡すだけです。int* *arr は以下の方法で。

void fun(const int n, const int m, int* *arr) {}

また、サイズが一定で、null で終了する配列を使用する場合は、必ずしも配列のサイズを追跡する必要はありません。定数整数変数の実際の値を使用して配列を malloc し、反復によって配列がスローされたときに終端の null バイトをチェックするだけです。

int* *arr = NULL;

if((arr = malloc(sizeof(int*)*6)) == NULL)'m'+1 = 6;
{
   perror("ERROR(1): Failed to allocate memory for the initial pointer address ");
   return 1;
}

for(i = 0; i < m; i++)
{
   if((arr = malloc(sizeof(int*)*4) == NULL)//'n'+1 = 4
   {
      perror("ERROR(2): Failed to allocate memory for a subsequent pointer address ");
      return 2;
   }
}

次に、次の方法で 2 次元配列全体を表示できます。'\000' は、ヌル バイト (00000000) の 8 進数の値であることに注意してください。

int i, j;
for(i = 0; arr[i] != '\000'; i++)
{
    for(j = 0; arr[i][j] != '\000'; j++)
    {
      printf("%i ", arr[i][j]); //Prints the current element of the current array
    }

    printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line. 
}

もちろん、上記のループは以下と同じ結果になります。

int i, j;
int m = 5;
int n = 3;

for(i = 0; i < m; i++)
{
    for(j = 0; i < n; j++)
    {
      printf("%i ", arr[i][j]); //Prints the current element of the current array
    }

    printf("\n"); //This just ends the line so that each of the arrays is printed on it's own line. 
}

つまり、ほとんどの場合、配列のサイズを追跡する必要はありませんが、必要な状況もあります。たとえば、配列に終端の null バイト以外の null バイトが含まれている可能性がある場合。新しいヌル バイトは、配列のサイズを新しいヌル バイトのインデックスに短縮します。ご質問やご意見がございましたら、お気軽に下にコメントするか、私にメッセージを送信してください。

于 2013-07-17T01:56:37.363 に答える