0

私は次のコードを試していました

#include<stdio.h>

int main()
{
    int A[3][4] = {{1,2,3,4},{5,6,7,8,},{9,10,11,12}};

    int **t = &A[0]; //I do this or **t = A,I guess both are equivalent


    printf("%d %p\n\n",*t,A[0]);

    return 0;

}

私が期待したこと:

ここで、t は A[0] のアドレスを保持する 2d ポインター (ポインターへのポインター) であり、A[0][0] のアドレスを保持します。したがって、 *t は A[0] の値、つまり A[0][0] のアドレスを提供し、 **t は A[0][0] の値を提供する必要があります。この場合は 1 です。 .

私が得たもの:

*t の値は 1 でした。セグメンテーション違反が発生したため、**t を見つけようとしてもできませんでした。

なぜこれが起こっているのか誰にも教えてもらえますか?

次の説明を試みましたが、それが「正しい」説明かどうかはわかりません。t は A[0] のアドレスを保持しますが、 A は配列であり、 A[0] は配列ポインター (「厳密には」ポインターではない) であるため、C はポインター A または A[0] にメモリを割り当てません。特に UNLIKE 他のポインター変数。配列全体にのみメモリを割り当てます。したがって、A[0] と A[0] (A[0][0] のアドレス) のアドレスは本質的に同じであり、両方とも 1 つの屋根の下に属しており、「別個の」エンティティとは異なります。その結果、t は間接的に A[0][0] のアドレスを保持し、*t は A[0][0] の値 (1) を与えます。

上記の説明は正しいですか?ちょっと奇妙に見えます。

4

2 に答える 2

2

配列はポインターではありません。

さて、さらに...

多次元配列は double、triple などのポインターではありません。

あなたのプログラムは未定義の動作を数回呼び出しますが、期待できるものはもありません。

配列がメモリ内で連続していることを考えると、次のように例を書き直すことができます。

int A[3][4] = {{1,2,3,4},{5,6,7,8,},{9,10,11,12}};
int *p = &A[0][0];

printf("%d %d %p\n", A[0][0], *p, (void *)p);
于 2013-04-12T21:03:35.917 に答える
0

次の説明を試みましたが、それが「正しい」説明かどうかはわかりません。

完全ではありませんが、やや近いです。

tのアドレスを保持しますがA[0]Aは配列でA[0]あり、配列ポインタであるため

A[0]配列です。具体的には、その型はint[4]です。

(これは「正確には」ポインターではありません)、Cはポインターにメモリを割り当てたり、他のポインター変数を特別にUNLIKEしAたりしません。A[0]

配列とポインタは、基本的に異なるタイプのエンティティです。それらを混同しないでください。

ほとんどの場合、型の式が(配列の最初の要素を指すarray of T) 型の値に変換されるという事実は、確かに混乱の原因となりますが、それが変換であることを忘れてはなりません。特に、高次元の配列、または配列の配列の場合、配列の要素の型自体が配列型であるため、変換の結果は配列へのポインターになります。pointer to T

配列全体にのみメモリを割り当てます。したがって、A[0]とのアドレスA[0]( のアドレスA[0][0]) は本質的に同じです。

いいえ、それらは本質的に異なります。1 つA[0]は配列 でint[4]あり、もう1 つは 4 つの&A[0]配列へのポインタです。どちらでもない。intint(*)[4]&A[0][0]

しかし、A[0]が最初の要素へのポインタに変換されると、&A[0][0]通常、結果のアドレスは のアドレスと同じになりますA[0](通常、オブジェクトへのポインタは、オブジェクトに属する最小アドレスを持つバイトのアドレスを保持しますA[0]。へ (の一部である)、A最も低いアドレスを持つもの、の一部である最初のバイトは、の一部でA[0]ある最初のバイトですA)。

したがって&A[0]&A[0][0]は通常同じ表現を持ちますが、一方は 、int(*)[4]もう一方はint*です。

両方とも 1 つの屋根の下に属し、「別個の」エンティティとは異なります。その結果t、 は間接的に のアドレスを保持し、の値A[0][0]*t与えますA[0][0]。これは 1 です。

その部分は、逆参照をt未定義の動作にする型の不一致は別として、多かれ少なかれ正しいです。正式には、未定義の動作により、あらゆることが起こります。

実際には、 if sizeof(int) == sizeof(int*)、逆参照は1 をアドレスとしてt解釈し、それを(さらに別の未定義の動作) として出力すると、出力されます。の場合、64 ビット システムで一般的であるように、逆参照は通常、2 つのと をまとめてアドレスとして解釈します。または、おそらくエンディアンに依存します。intA[0][0]int1sizeof(int*) == 2*sizeof(int)tintA[0][0]A[0][1]0x2000000010x100000002

于 2013-04-12T21:55:31.940 に答える