10

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;
}
4

5 に答える 5

21

dataは2次元配列で、4行あり、各行には3つの要素(つまり、4 X 3)があります。

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

次に*Ptr*(Ptr + 0)またはは、ポイントしている行の最初の要素の値を示します。同様に*(Ptr + 1)、行の2番目の要素の値が表示されます。

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

配列について考えてみましょう。あなたがそれを知っていて、同じint a[5];であることを願っています。これは、を意味し、を意味するためです。これと同じロジックを2次元配列で使用できます。a[0]0[a]a[0]*(a+0)0[a]*(0 + a)

data[i][j]に似てい*(*(data + i) + j)ます。として書くことi[data][j]もできます。

詳細については、YashavantKanetkarの著書「UnderstandingPointersinC」を参照してください。

于 2012-06-24T13:29:03.000 に答える
7

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

一般に、p をポインタ名、i 行番号、j 列番号とすると、

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

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

于 2015-06-11T12:33:21.207 に答える
1

data整数の 3 要素配列の配列です。「fooへのポインター」を期待するコンテキストでは、「fooの配列」を使用できます。これは、最初の要素へのポインターのように動作するため*data、の最初の要素へのポインターdata、つまり(いわば){23,55,50}です。

したがって、コメントの最初の質問に対する答え: いいえ、そうではありませんPtr = 23。(ありえません;Ptrは でありint *、23 はintです。)

の番目の行をPtr = *(data+i)指摘Ptrするあなたは正しいです。より正確には、int の 3 要素配列の配列であり、int の 3 要素配列へのポインターのように動作します。それに追加すると、そのような配列を通過します。idatadataii

配列の他の列にアクセスする通常の方法は、通常の配列インデックスです。を参照すると、行の列をdata[i][j]取得しています。明示的なポインター演算でそれを行いたい場合は、(たとえば)コード例では「整数へのポインター」型であるため、 (たとえば) 行が指している行の要素 1 であることに注意してください。(ただし、スタイルの問題として、実際に必要がない場合は、通常、明示的なポインター演算を行うべきではありません。)jiPtrPtr+1Ptr

于 2012-06-24T12:35:04.897 に答える
0

この例では、ループはすべての行列行を調べて、すべての要素の合計が最大値を保持している行を見つけます。

最初に、最初の行へのポインタが割り当てられます。

Ptr = *data;

これは、次のことが当てはまることを意味します。

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

Ptrはポインタであるため、メモリアドレスを保持しているため、Ptrは23は異なります(メモリアドレスが23である場合を除き、発生する可能性は低いです)。

于 2012-06-24T12:41:16.703 に答える
0

C は多次元配列を許可し、連続した場所としてメモリに配置し、舞台裏でより多くのアドレス演算を行います。2 次元配列を考えてみましょう。

int arr[ 3 ][ 3 ] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

コンパイラは、2 次元配列を配列の配列として扱います。ここで、配列名は配列内の最初の要素へのポインターです。したがって、arr は最初の 3 要素配列を指します。これは、実際には 2 次元配列の最初の行 (つまり、行 0) です。同様に、(arr + 1) は 2 番目の 3 要素配列 (つまり、行 1) を指し、以下同様です。このポインターの値(arr + 1) は、行全体を参照します。行 1 は 1 次元配列であるため、(arr + 1) は実際には行 1 の最初の要素へのポインターです。このポインターに 2 を加算します。したがって、( (arr + 1) + 2) は、行 1 の要素 2 (つまり、3 番目の要素) へのポインターです。このポインターの値( (arr + 1) + 2) は、列の要素を参照します。行 1 の 2。

于 2020-08-28T08:00:27.790 に答える