14

配列がポインタに減衰することを知っています。

char things[8];

その後、別の場所で使用されるthingsthingsは、配列の最初の要素へのポインタです。

また、私の理解から、

char moreThings[8][8];

減衰は1回だけ発生するため、charへのポインタ型でmoreThingsなく「charへのポインタの配列」型になります。

いつmoreThings関数に渡されますか(プロトタイプvoid doThings(char thingsGoHere[8][8])では、スタックで実際に何が起こっているのでしょうか?

がポインタ型でない場合moreThings、これは本当に参照渡しですか?moreThingsそれでも多次元配列のベースアドレスを表しているといつも思っていたと思います。doThings入力を受け取りthingsGoHere、それ自体が別の関数に渡した場合はどうなりますか?

配列入力を指定しない限りconst、配列は常に変更可能であるという規則はほとんどありますか?

型チェックはコンパイル時にのみ行われることは知っていますが、技術的には参照によるパスとしてカウントされるものについてはまだ混乱しています(つまり、型ポインターの引数が渡された場合のみ、またはポインターの配列がパスになる場合のみです-参照によっても?)

この質問で少しいたるところにいて申し訳ありませんが、これを理解するのが難しいため、正確な質問を明確にするのは難しいです。

4

3 に答える 3

27

少し間違っていmoreThingsます。最初の要素へのポインタにも減衰しますが、これは文字の配列の配列であるため、最初の要素は「8文字の配列」です。したがって、減衰したポインタは次のタイプです。

char (*p)[8] = moreThings;

ポインタのはもちろん、の値&moreThings[0][0]、つまり最初の要素の最初の要素の値と同じであり、また同じです&aが、タイプはそれぞれ異なるものです。

次の場合の例を次に示しますchar a[N][3]

+===========================+===========================+====
|+--------+--------+-------+|+--------+--------+-------+|
|| a[0,0] | a[0,1] | a[0,2]||| a[1,0] | a[1,1] | a[1,2]|| ...
|+--------+--------+-------+++--------+--------+-------++ ...
|            a[0]           |            a[1]           |
+===========================+===========================+====
                                    a
^^^
||+-- &a[0,0]
|+-----&a[0]
+-------&a
  • &a:charsの配列の配列全体のアドレス。これはchar[N][3]

  • &a[0]、と同じa:それ自体が最初の要素のアドレスchar[3]

  • &a[0][0]:最初の要素の最初の要素のアドレス。char

これは、異なるオブジェクトが同じアドレスを持っている可能性があることを示していますが、2つのオブジェクトが同じアドレス同じタイプを持っている場合、それらは同じオブジェクトです。

于 2012-10-01T13:24:35.093 に答える
19

「アレイアドレスと多次元アレイへのポインタ」

まず、1-D配列から始めましょう。

  • 宣言char a[8];により、8つの要素の配列が作成されます。
    そして、ここa最初の要素のアドレスがありますが、配列のアドレスではありません

  • char* ptr = a;ptrcharへのポインタと 同様に正しい式であり、最初の要素をアドレス指定できます。

  • しかし、表現ptr = &a間違っています!ptr配列をアドレス指定できないためです。

  • &aは配列のアドレスを意味します。aとの実際の値&aは同じですが、意味的には両方が異なります。1つは文字のアドレスで、もう1つは8文字の配列のアドレスです。

  • char (*ptr2)[8]; ここでptr2 is pointer to an array of 8 chars、そして今回 ptr2=&aは有効な表現です。

  • isのデータ型と&aisのchar(*)[8]型はa、ほとんどの操作char[8]で単純に減衰します。char*char* ptr = a;

    よりよく読むために:との違いchar *strchar str[]両方がメモリに保存する方法は?

2番目のケース、

  • 宣言により、サイズ char aa[8][8];の2次元配列が作成されます。8x8

  • 任意の2次元配列は、各配列要素が1次元配列である1次元配列と見なすこともできます

  • aa8文字の配列である最初の要素のアドレスです。式ptr2 = aaは有効で正しいです。

  • 次のように宣言した場合:

    char (*ptr3)[8][8];    
    char ptr3 = &aa;  //is a correct expression
    

    同様に
    moreThings、宣言char moreThings[8][8];には、8要素のchar配列であるfist要素のアドレスが含まれています。

    よりよく読むために:との違いchar* str[]char str[][]両方がメモリに保存する方法は?


知っておくと面白いでしょう:

  • morething8文字の配列のアドレスです。

  • *morethingである最初の要素のアドレスです&morething[0][0]

  • &morething8x8の2次元配列のアドレスです。

    また、上記の3つすべてのアドレス値は同じですが、意味的にはすべて異なります。

  • **morethingである最初の要素の値ですmorething[0][0]

    よりよく読むために:との違い&strstrいつstrが?として宣言されているchar str[10]

さらに、

  • void doThings(char thingsGoHere[8][8])はvoiddoThings(char (*thingsGoHere)[8])に過ぎないため、2次元で2次元が8の配列を受け入れます。

CおよびC++の変数のタイプについて:(回答を追加したい)

  • CのC++の概念では、参照によって何も渡されません。Cで使用されている場合、それは作成者がポインタ変数について話していることを意味します。
  • Cはとをサポートpass by Addresspass by valueます。
  • C ++は、、およびをサポートPass by addresspass by valueますpass by Reference

    読み取り:ポインター変数と参照変数

最後に、

  • 配列の名前は、変数ではなく定数識別子です。
于 2012-10-01T13:57:12.550 に答える
5

ケレクによってうまく説明された、

それに加えて、次の例でそれを証明できます。

#include <stdio.h>

int main ()
{
 int a[10][10];

 printf (".. %p  %p\n", &a, &a+1);
 printf (".. %p  %p \n ", &a[0], &a[0]+1);
printf (".. %p   %p \n ", &a[0][0], &a[0][0] +1);
}

出力は次のとおりです。

.. 0x7fff6ae2ca5c  0x7fff6ae2cbec    = 400 bytes difference
.. 0x7fff6ae2ca5c  0x7fff6ae2ca84    = 40 bytes difference
 .. 0x7fff6ae2ca5c   0x7fff6ae2ca60  = 4 bytes difference. 

&a+1->配列全体のサイズを追加してポインタを移動します。すなわち:400バイト

&a [0]+1->列のサイズを追加してポインタを移動します。すなわち:40バイト。

&a [0] [0] +1->要素のサイズ(4バイト)を追加してポインタを移動します。

[intサイズは4バイトです]

お役に立てれば。:)

于 2012-10-01T13:57:22.960 に答える