2012-06-24 10 views
5

私は、2D配列へのポインタを含む例を持っています。この例で何が起こっているのか誰かが理解できるように助けることができますか?Cの2D配列とポインタ - 要素へのアクセス方法?

int main() 
{ 

    int i = 0, j=0, sum0=0, sum1=0; 
    int data[4][3] = { {23,55,50},{45,38,55},{70,43,45},{34,46,60}}; 
    int *Ptr; 
    Ptr = *data; //Why is the indirection operator used here? 
        // Does Ptr = 23 by this assignment? 

    for (i=0; i<4; i++) { 
     sum1 = 0; 
     for (j = 0; j < 3; j++) { 
      sum1 += data[i][j]; 
     } 
     if (sum1 > sum0) { 
       sum0 = sum1; 
       Ptr = *(data + i);  // Seems like this statement makes Ptr 
     }        // point one row below ... what syntax 
    }         // can you use to access columns then? 
             // Is it possible to use pointer arithmetic 
    for (i=0; i<3; i++)     // to access elements of data[i][j] that 
     printf("%d\n", Ptr[i]);   // are not at j = 0? 

    return 0; 
} 
+0

こちら[タグ:宿題]ですか? – Alexander

+0

私はイントロのCSコースを取っていた、これは私の講義ノートから与えられた単なる例でした。 – shafools

答えて

13

dataは2次元配列であり、4行あり、各行は3要素(すなわち4×3)を有する。

ここで、Ptr = *data;は、ポインタ変数Ptrに1行目の開始アドレスを格納することを意味します。このステートメントはPtr = *(data + 0)に相当します。 Ptr = *(data + 1) - これは、2行目の開始アドレスを割り当てていることを意味します。

次に、*Ptrまたは*(Ptr + 0)は、あなたが指している行の最初の要素の値を与えます。同様に、*(Ptr + 1)は行の2番目の要素の値を返します。

プログラムのループは、要素の合計(3要素)の最大値を持つ行を識別するために使用されます。ループがforループから抜けると、Ptrは要素の最大合計を持つ行を指し、sum0は合計の値を持ちます。

配列int a[5];を考えると、a[0]0[a]が同じであることをご存じでしょうか。これは、a[0]*(a+0)を意味し、0[a]*(0 + a)を意味するためです。この同じ論理を2次元配列で使用することができます。

data[i][j]は、*(*(data + i) + j)と同様です。 i[data][j]と書くこともできます。

詳細については、yashwant kanetkarの書籍「understanding pointer in c」を参照してください。

1

dataは、整数の3要素配列の配列です。 "fooへのポインタ"を期待する文脈では、 "fooの配列"を使うことができ、その最初の要素へのポインタのように振る舞います。したがって*datadataの最初の要素へのポインタです。 {23,55,50}

コメントの最初の質問に対する答え:いいえ、Ptr = 23ではありません。 (それはあることができなかった。Ptrint *と23 intである。)Ptr = *(data+i)datai行目にPtrポイントを作ることをあなたが正しい

。より正確には、dataは、intの3要素配列へのポインタのように動作するintの3要素配列の配列です。それにiを追加すると、iのような配列が移動します。

配列の他の列にアクセスする通常の方法は、通常の配列のインデックス付けです。 data[i][j]を参照している場合は、行の列jが表示されます。明示的なポインタ算術を使用したい場合、例コードのPtrは "整数へのポインタ"型であるため、Ptr+1(たとえば)は、Ptrが指している行の要素1です。 (しかし、スタイルの問題として、実際には必要ないときには、明示的なポインタ演算は行わないでください)。

0

この例では、ループはすべての行列の行を調べて、最大値を保持します。

Ptr = *data; 

次が真であることを意味します:それは保持しているので、のPtrはポインタがある

(Ptr[0] == 23 && Ptr[1] == 55 && Ptr[2] == 50) 

お知らせすることを最初の行へのポインタが割り当てられている冒頭

したがってメモリアドレスが である場合を除き、Ptrはとは異なります。 23、これは起こりそうにありません)。

4

Ptr = *data;は、最初の行の最初の列要素のポインタである*(data+0)+0の略です。データが追加された最初の0は行番号であり、これは間接的なもので、最初の行に移動します。 * (data+0)は依然としてアドレスであり、それがポイントする値ではありません(2D配列の場合)。したがって、Ptrは最初の行の最初の列のアドレスを指します。 2番目のゼロは列番号です。したがって、最初の行と最初の列のメモリアドレスが選択されます。インダイレクション(*)を使用すると、アドレスに保持されている値だけが返されます。 * (*(data+0)+0)または**dataのようになります。 pはポインタ名である場合

一般に、私は数及びj列番号、

  1. (*(p+i)+j)は、二次元配列の要素のメモリアドレスを与える行。私は行番号です。 jは列番号です。
  2. *(*(p+i)+j)は、その要素の値を返します。
  3. *(p+i)は、列にアクセスするために
  4. にアクセスし、列番号を*(p+i)に追加します。 *pではなく、ポインタを(*p)[columns]と宣言する必要があります。そうすることで、2D配列へのポインタを宣言しています。

ポインタ演算を使用すると、1次元配列のように2次元配列が処理されます。ポインタ* Ptrを最初の要素(int *Ptr = *data)に初期化してから、no。 (Ptr + n)を使用して列にアクセスします。列番号よりも高い番号を追加すると、次の行の最初の列が存在する場合は、その要素を数え続けます。