2

以下の機能で何が違うのか、簡単に説明してもらえますか?

    void f1(data_t **d)
    {
        for (int i=0; i<MAXSIZE; i++)
        {
            (*d)[i].ival = i;
        }
    }

    void f2(data_t **d)
    {
        for (int i=0; i<MAXSIZE; i++)
        {
            (*d)->ival = i;
            (*d)++
        }
    }

    void f3(data_t *d)
    {
        for (int i = 0; i<MAXSIZE; i++)
        {
            d->ival = i;
            d++;
        }
    }

    void f4(data_t *d)
    {
        for (int i = 0; i<MAXSIZE; i++)
        {
            d[i].ival = i;
        }
    }

特に f2 で何が違うのか。しかし、それぞれで明らかに異なることが起こっています。

f1 と f3 は同じことをします (ただし、異なる)。f2 は完全に失敗し、f4 はバグがあります (この例では機能しますが、他の値を他のポインター (char *) に入れようとすると、文字列がおかしくなります。)

4

3 に答える 3

2
void f1(data_t **d)
{
    for (int i=0; i<MAXSIZE; i++)
    {
        (*d)[i].ival = i;
    }
}

d は、data_t の配列へのポインターのようです (または、data_t の配列の 1 要素配列です)。data_t の配列を復元するために逆参照され、この配列の i 番目の要素が変更されます。

void f2(data_t **d)
{
    for (int i=0; i<MAXSIZE; i++)
    {
        (*d)->ival = i;
        (*d)++
    }
}

これは少しトリッキーで、実際に最初のケースとは異なることを行います。data_t の配列へのポインタがありました。ここに、data_t へのポインターの配列があります。最初の要素へのポインターは、データへのポインターを取得するために逆参照されます。次に、 -> を使用してデータにアクセスし、値を変更します ( x->y = (*x).y )。最後に、ポインターはメイン配列の次の要素に移動されます。

void f3(data_t *d)
{
    for (int i = 0; i<MAXSIZE; i++)
    {
        d->ival = i;
        d++;
    }
}

ここでは、より単純なケースがあります。d は、ポインターによってアクセスされる data_t の単なる配列です。ループ内では、要素が -> によってアクセスされ、d がインクリメントされて配列の次の要素を指します。

void f4(data_t *d)
{
    for (int i = 0; i<MAXSIZE; i++)
    {
        d[i].ival = i;
    }
}

f3 と同様に、要素は [] 演算子によって変更されます。

次の事実に注意してください。

int[] =(def) int *

a が int * 型で i が任意の整数型の場合:

*(a + i) =(def) a[i]

また、 a が配列の最初の要素を指している場合、

*a =(def) a[0]

そして、「a++」の後

*a =(def) a[1]

...等々。

于 2012-04-11T07:06:35.823 に答える
1
 void f1(data_t **d) 
    { 
        for (int i=0; i<MAXSIZE; i++) 
        { 
            (*d)[i].ival = i; 
        } 
    } 
  1. 要素が構造体で、フィールドを持つ の配列へ**dのポインタを取得しますdata_tival
  2. 配列にアクセスする*d
  3. すべての配列要素を要素ごとに繰り返し、インデックスを変更します。そして、各配列要素を次のようにi更新しますivali

注: t change the pointer*d`, 配列の先頭を指すことはありません

void f2(data_t **d) 
{ 
    for (int i=0; i<MAXSIZE; i++) 
    { 
        (*d)->ival = i; 
        (*d)++ 
    } 
} 
  1. 要素が構造体で、フィールドを持つ の配列へ**dのポインタを取得しますdata_tival
  2. *d配列へのポインタでもある配列にアクセスします(最初の要素)
  3. ポインター表記を使用しivalて、be による (上記の) 要素の更新i(*d)->ival = i;
  4. ポインタを次の配列要素に昇格させて、これから先(*d)++に戻り2.ます *d は、「ふるいにかけた」配列の先頭を指しています。

    ボイド f3(data_t *d)

    { 
       for (int i = 0; i<MAXSIZE; i++) 
       { 
          d->ival = i; 
          d++; 
       } 
    } 
    

    1.要素が構造体であり、フィールドを持つの配列*dを取得します。data_tival

    2.また、配列の最初の要素へのポインターを取得すると見なすこともできます。アクセスにアクセスし、ポインターによって次のivalように更新します。id->ival = i;

    3.ポインタを次の配列要素に昇格させるd++

    ボイド f4(data_t *d)

    { 
       for (int i = 0; i<MAXSIZE; i++) 
       { 
          d[i].ival = i; 
          d++; 
       } 
    } 
    

のように。ただし、f3インデックスを昇格させival、参照表記を使用して更新します (値による) 。

于 2012-04-11T07:25:33.507 に答える
1

これらを 1 つずつ取り上げてみましょう。

// f1
(*d)[i].ival = i;

まず、(*d)逆参照です。これは、変数dの配列へのポインターのように見えます。これにより、配列の 番目の要素にアクセスして代入するdata_tなど、実際の配列にアクセスできます。[i]ii

// f2
(*d)->ival = i;
(*d)++;

(*d)d最初のものと同じように逆参照しています。ただし、先に進む前に理解しておくべき配列に関する重要な情報が 1 つあります...

int j[2] = { 42, 50 };
int j0 = *j; // j0 is now 42
j += 1;
int j1 = *j; // j1 is now 50

配列は、メモリ内の「スロット」に順番に並べられた個々の変数として実装されます。配列は、実際には最初のスロットへの単なるポインターです。そのため、現在最初の要素を指している*j逆参照であり、結果として. を行うと、ポインターが 1 つの「スロット」だけ進み、結果として.j42j += 1*j50

に戻りf2ます。(*d)->ivalのよう(**d).ivalです。これは、上で示した単純な例と非常によく似ています。次の行 は(*d)++、ポインターを次の「スロット」に進めています。メモリ内で何が「起こっている」かを示す次の簡単な図を考えてみましょう。

      +------+------+
      |*(j+0)|*(j+1)|
j --->|------|------|
      |  42  |  50  |
      +------+------+

最初の「スロット」をj指し、最初の行に逆参照、2 番目の行に値を示します。

f3は に非常によく似f2ていますが、配列へのポインターではなく、引数として配列が渡されることを期待している点が異なります。したがって、演算子dを使用して逆参照する必要があるのは 1 回だけです->(これも とまったく同じです(*d).ival)。

f4は に非常によく似f1ていますが、配列へのポインターではなく、引数として配列が渡されることを期待している点が異なります。したがって、配列の -i 番目の要素にd[i]直接アクセスしています。i

于 2012-04-11T07:08:05.017 に答える