5

2つの異なる方法でCで2つの2D配列(行列)を作成しました。
それらがメモリで表される方法の違いと、同じようにそれらを参照できない理由がわかりません。

scanf("%d", &intMatrix1[i][j]); //can't refer as  &intMatrix1[(i * lines)+j])

scanf("%d", &intMatrix2[(i * lines)+j]); //can't refer as &intMatrix2[i][j])

これらの2つの配列の実装方法の違いは何ですか?また、なぜそれらを異なる方法で参照する必要があるのですか?

(関数??????内で)同じ方法で各配列の要素を参照するにはどうすればよいですか?printMatrix

int main()
{
   int **intMatrix1;
   int *intMatrix2;

   int i, j, lines, columns;

   lines = 3;
   columns = 2;

   /************************* intMatrix1 ****************************/

   intMatrix1 = (int **)malloc(lines * sizeof(int *));

   for (i = 0; i < lines; ++i)
      intMatrix1[i] = (int *)malloc(columns * sizeof(int));

   for (i = 0; i < lines; ++i)
   {
       for (j = 0; j < columns; ++j)
       {
       printf("Type a number for intMatrix1[%d][%d]\t", i, j);
       scanf("%d", &intMatrix1[i][j]); 
       }
   }

   /************************* intMatrix2 ****************************/ 

   intMatrix2 = (int *)malloc(lines * columns * sizeof(int));

   for (i = 0; i < lines; ++i)
   {
       for (j = 0; j < columns; ++j)
       {
       printf("Type a number for intMatrix2[%d][%d]\t", i, j);
       scanf("%d", &intMatrix2[(i * lines)+j]);
       }
   }

   /************** printing intMatrix1 & intMatrix2 ****************/

   printf("intMatrix1:\n\n");
   printMatrix(*intMatrix1, lines, columns);

   printf("intMatrix2:\n\n");
   printMatrix(intMatrix2, lines, columns);
}


/************************* printMatrix ****************************/

void printMatrix(int *ptArray, int h, int w)
{
    int i, j;

    printf("Printing matrix...\n\n\n");

    for (i = 0; i < h; ++i)
        for (j = 0; j < w; ++j)
        printf("array[%d][%d] ==============> %d\n, i, j, ??????);
}
4

4 に答える 4

5

Matrix12回間接参照しています。

Matrix1[i][j] ;

これは、2D配列またはこのように宣言されたダブルポインタであることを意味します。

int **Matrix1 ;

Adouble pointerはポインタの配列と考えることができます。その各要素はそれ自体がポインターであるため、ポインター要素に到達するために1回逆参照され、そのメンバーのポインターまたは配列のデータメンバーにアクセスするために2回逆参照されます。あなたが書いたこのステートメントは、これと同等です。

Matrix1[i][j] ;   //is ~ to

*( *(Matrix1 + i) + j) ;

このような単一のポインタの場合。

int *Matrix2 ;

このように、一度だけ参照解除できます。

Matrix2[i] ;  //is ~ to
*(Matrix2 + i) ;

あなたが書いたこの声明。

Matrix2[(i * lines)+j] ;
         |-----------|

この部分は単一の数値に評価されるため、1回参照解除されます。

(i * lines) + j ;

printmatrix()関数に関しては、渡さptArrayれるのは単一のポインターです。したがって、2回逆参照することはできません。

おそらく、ここでの私の答えから、静的および動的2D配列の理解を深めることができます。

関数の引数としての2D配列

于 2012-10-08T15:21:14.363 に答える
3

両方の行列は、メモリ内のバイトのシーケンスです。ただし、これらの違いは、行列を表すためにメモリインターフェイスを定義する方法です。1つのケースでは、マトリックス内の要素と等しい要素数でメモリセグメントを定義しているだけであり、他のケースでは、特定の各行を表すためにメモリを具体的に割り当てています。

次のケースは、 malloc()を何度も呼び出すため、計算コストが高くなります。

intMatrix1 = (int **)malloc(lines * sizeof(int *));
for (i = 0; i < lines; ++i)
  intMatrix1[i] = (int *)malloc(columns * sizeof(int));

ただし、マトリックス要素をより明確に参照できるという利点があります。

intMatrix1[i][j];

マトリックス内の要素の数に等しい要素のシーケンスを1つだけ割り当てる場合は、行/列のインデックス計算を考慮して、メモリ内の適切なマトリックス要素を参照する必要があります。

コードの均一性を高めるために、行列の行参照と行列の列数を受け取り、行を出力する関数を提案できますか?

void PrintLine(int *ptrLine, int lineLen) {
   unsigned int i;
   for(i = 0; i < lineLen; i++)
      printf("%d ", ptrLine[i]);
   printf("\n");
}

次に、マトリックスタイプごとに、次のようにします。

// Case 1
for(i = 0; i < lines; i++)
   PrintLine(intMatrix1[i], columns);
// Case 2
for(i = 0; i < lines; i++) {
   PrintLine(intMatrix2 + i*columns, columns);
}
于 2012-10-08T15:22:41.880 に答える
2

違いは、最初の配列は次のとおりです。

intMatrix1 = (int **)malloc(lines * sizeof(int *));

ポインタの配列を作成しますintMatrix1。これらの各ポインターは、int配列(ここではmalloc)を指します。

for (i = 0; i < lines; ++i)
   intMatrix1[i] = (int *)malloc(columns * sizeof(int));

そのため、単一の要素にアクセスするには、宣言に2つの星(ポインター配列、次にint配列への逆参照)と二重括弧が必要です。

int **intMatrix1;

int i = intMatrix[row][column];
int i = *(*(intmatrix + row) + column);

2番目の行列では、サイズ列*行のint配列のみを作成します。

int *intMatrix2 = (int *)malloc(lines * columns * sizeof(int));

int i = intMatrix[row + column];
int i = *(intMatrix + row + column);

2つの配列を印刷するには、2つの行列の内部構造が異なるため、異なる印刷関数を使用する必要がありますが、両方の配列にアクセスするためのさまざまな方法をすでに知っています。

于 2012-10-08T15:21:23.747 に答える
2

Cでは、配列アクセス演算子[]は実際にはポインター演算を実行するためのよりクリーンな方法です。タイプの要素の1次元配列の場合、はとtype_s同等arr[i]です*(arr + (i * sizeof(type_s)))。その表現を分析するには:

  • arrベースアドレス、この配列が格納されている最小のメモリアドレスになります
  • i配列内の要素のゼロインデックス位置です
  • sizeofの要素がメモリで使用するcharsの数(通常はバイト数と同じですが、C仕様では必須ではありません)を返します。arrコンパイラは要素のサイズを決定し、この計算を自動的に実行します。

arr[i]補足として、この構文には、と同等の副作用がありますがi[arr]、インデックスを角かっこで囲むことは広く受け入れられています。

以上のことをすべて踏まえて、2つの宣言の違いを見てみましょう。

intMatrix1[i][j]と同等*(*(intMatrix1 + i * sizeof(int)) + j * sizeof(int))です。したがって、その式には2つの間接参照演算子があります。つまり、intMatrixは配列の配列です(ポインターへのポインターが含まれています)。

一方、intMatrix2[(i * lines)+j]は、に相当し*(intMatrix2 + ((i * lines) + j) * sizeof(int))ます。これには、間接参照演算子が1つだけ含まれています。ここで行っているのは、元の2次元配列と同じ数の要素を含む1次元配列を定義することです。データをマトリックスで最もよく表すことができる場合は、最初のバージョンを使用することをお勧めしますintMatrix1[i][j]

于 2012-10-08T15:24:23.213 に答える