2017-01-14 15 views
1

2d配列を関数に入力するときにこのエラー(画像1)が発生したのはなぜですか?int型のパラメーターにint [5] [5]を渡す互換性のないポインター型**

enter image description here

#include <stdio.h> 
#include <stdlib.h> 
void pr(int** a){ 
    printf("%d", a[0][0]); 
} 

int main(){ 
    int a[5][5]={{1,4,7,11,15},{2,5,8,12,19},{3,6,9,16,22},{10,13,14,17,24},{18,21,23,26,30}}; 
    pr(a); 
} 
+2

配列とポインタは同じではなく、ポインタへのポインタは2次元配列と同じではありません。 'void pr(int a [] [5])'やそれに類するものを使うべきです。 –

+0

関数prを変更できない場合はどうなりますか? – user7341005

+4

次に、 'main()'に異なる配列構造体が必要です: 'int * a [] = {(int []){1,4,7,11,15}、(int []){2,5、 8、12、19}、(int []){3、6,9,16,22}、(int []){10,13,14,17,24}、(int []){18,21 、23、26、30}}; ' - コンパイルされていないので、エラーが発生する可能性があります。私はC99複合リテラルを使用しています。これは 'int'へのポインタの配列を与えますが、各ポインタは' int'の配列の先頭にあります。 –

答えて

5

コアの問題は、配列とポインタが同じではなく(それらは密接に関連していますが)、2D配列はポインタの配列ではないということです。

このコードは、問題を解決する3つの方法を示しています。配列a0は配列の名前が変更され、再フォーマットされます。配列aはポインタの配列であり、各ポインタはC99に追加された「複合リテラル」を介して5 intの配列へのポインタです。私は渡された配列の25要素すべてを印刷するように印刷機能をアップグレードしました。また、渡された配列全体を印刷する異なるインタフェースを持つ2つの新しい印刷関数を作成しました。私は配列が正方形であると仮定します。 のようなのような変形では、pr1()とほとんど同じですが、nの代わりにjjに対してテストするために内部的に調整する必要がある場合は、長方形(非正方形)の行列を簡単に処理できます。

#include <stdio.h> 

static void pr0(int a[][5]); 
static void pr1(int n, int a[n][n]); 

static void pr(int **a) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     for (int j = 0; j < 5; j++) 
      printf("%3d", a[i][j]); 
     putchar('\n'); 
    } 
    putchar('\n'); 
} 

int main(void) 
{ 
    int a0[5][5] = 
    { 
     { 1, 4, 7, 11, 15 }, 
     { 2, 5, 8, 12, 19 }, 
     { 3, 6, 9, 16, 22 }, 
     { 10, 13, 14, 17, 24 }, 
     { 18, 21, 23, 26, 30 }, 
    }; 
    int *a[] = 
    { 
     (int[]){ 1, 4, 7, 11, 15 }, 
     (int[]){ 2, 5, 8, 12, 19 }, 
     (int[]){ 3, 6, 9, 16, 22 }, 
     (int[]){ 10, 13, 14, 17, 24 }, 
     (int[]){ 18, 21, 23, 26, 30 }, 
    }; 

    pr(a); 
    pr0(a0); 
    pr1(5, a0); 

    return 0; 
} 

static void pr0(int a[][5]) 
{ 
    for (int i = 0; i < 5; i++) 
    { 
     for (int j = 0; j < 5; j++) 
      printf("%3d", a[i][j]); 
     putchar('\n'); 
    } 
    putchar('\n'); 
} 

static void pr1(int n, int a[n][n]) 
{ 
    for (int i = 0; i < n; i++) 
    { 
     for (int j = 0; j < n; j++) 
      printf("%3d", a[i][j]); 
     putchar('\n'); 
    } 
    putchar('\n'); 
} 

サンプル出力は、驚くほど均一である:

1 4 7 11 15 
    2 5 8 12 19 
    3 6 9 16 22 
10 13 14 17 24 
18 21 23 26 30 

    1 4 7 11 15 
    2 5 8 12 19 
    3 6 9 16 22 
10 13 14 17 24 
18 21 23 26 30 

    1 4 7 11 15 
    2 5 8 12 19 
    3 6 9 16 22 
10 13 14 17 24 
18 21 23 26 30 

三つのブロックが同じです。選択肢があれば、インターフェイスでVLA(可変長配列)を使用してpr1()というテクニックを使用します。 int **引数を使用する必要がある場合は、配列aなどと非常によく似ている必要があります。確かにそれを作成する他の方法があります。例:

int *a[] = { a0[0], a0[1], a0[2], a0[3], a0[4] }; 
4

配列とポインタはすべての可能なユースケースでは交換可能に使用することはできない、とあなたはそれらの一つにつまずくことが起こります。時々、int配列は暗黙的にポインタに変換されることがあり、時にはそうではありません。

aが2次元配列の最初の要素をポインターと見なしているため、暗黙的に(または明示的に)aを(int **)に変換することはできません。 aをint **に変換すると、praの情報を配列として失うことになります。したがって、それを典型的なもの(int **)として扱い、それを2回参照解除しようとすると、aa[0][0] = 1)の最初の要素がアドレスとして扱われ、そのアドレスの値が検索されます希望の動作はpr()です。

ではなく、パラメータとして2D配列を使用するように、prを宣言するのが理想的です。前述のの修正を持つprの宣言を以下に示します。今

void pr(int a[][5]){ 
    printf("%d", a[0][0]); 
} 

、あなたはprの定義が変更できないことをあなたの質問にコメントで言及。 pr()を変更しないようにするには、mainのデータ構造を次のようなものに変更する必要があります。

int main(){ 
    int a0[5]={1,4,7,11,15}; 
    int a1[5]={2,5,8,12,19}; 
    int a2[5]={3,6,9,16,22}; 
    int a3[5]={10,13,14,17,24}; 
    int a4[5]={18,21,23,26,30}; 
    int *a[5] = {a0, a1, a2, a3, a4}; 
    pr(a); 
} 

上記のサンプルは、目的を達成するための最も構文的に簡潔な方法ではありません。また、hereにチェックすると、この使用方法がわかります。

関連する問題