• ベストアンサー

ポインタについて

配列のポインタについて教えてください。 int array[2][2]={1,2,3,4}; int *p; のような場合、 p=array;  にするとエラーがでますが、なぜですか? (p=(int *)array;のようにキャストすれば平気) _1_2_3_4_という風にメモリー上に並んでいますよね? 配列の場合array(&array[0][0])はこのメモリーの1が格納されているアドレスを指すわけですが、これをポインタpに入れるとなにか問題でも起こるんですか?

質問者が選んだベストアンサー

  • ベストアンサー
noname#15691
noname#15691
回答No.6

#1のmk7193hsです。 > p++;とすれば、p[0][0]の位置からp[0][1]のアドレスを指すようになって、さらにもう一回p++;をすれば、p[0][1]からp[1][0]を指すよになるのではとおもったのですが、だめなのでしょうか? 駄目ではありません。 int array[2][2]; int *p; と宣言した場合、要素はarray[0][0]、array[0][1]、array[1][0]、array[1][1]の順に並びますし、 p = (int *)array; とキャストして代入すれば、p++はarray[0][1]を、更にp++はarray[1][0]を示します。 ただ、 p = array; は、「型が違うので直接は代入できませんよ」という意味で、コンパイラはエラーを出しているのです。 このあたりを、正確に理解されたいのであれば、 「秘伝C言語問答 ポインタ編」参考URLへ という本を読むことをお薦めします。 p.s. 1 C言語ではarrayと&array[0][0]は必ず同じアドレスであり、コンパイラ依存ではありません。 2 arrayは「配列のポインタ」であって「ポインタの配列」ではありません。

参考URL:
http://www.amazon.co.jp/exec/obidos/ASIN/4797318260/250-2109625-3690664
tattin894
質問者

お礼

みなさま回答ありがとうございました。 まだよくわからないところがあるのでポインタの本を一冊かってみようとおもいます。

すると、全ての回答が全文表示されます。

その他の回答 (5)

  • ency
  • ベストアンサー率39% (93/238)
回答No.5

int array[2][2] = {1,2,3,4}; これは次のように代入したものと同じですよね? int array[2][2]; array[0][0] = 1; array[0][1] = 2; array[1][0] = 3; array[1][1] = 4; で、これをポインタ p に代入する場合は、次のようにする必要があるというのは、No1 mk7193hs さんのご回答のとおりです。 int (*p)[2]; p = array; 理由は、C では、コンパイラによって配列が先頭要素を指すポインタに読み替えられるためです。 要素数が同じでわかりにくいので、こんな例にしてみます。 -------------------------------------------------------- int array1[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; int (*p1)[3]; p1 = array1; printf( "%d\n", p1[1][1] ); /* → 5 が表示される */ -------------------------------------------------------- この場合、array1 は「『intの配列(要素数3)』の配列(要素数2)」となります。 これをコンパイラは「『intの配列(要素数3)』の配列(要素数2)の先頭要素を指すポインタ」に読み替えます。 つまり、型は「『intの配列(要素数3)』を指すポインタ型」になります。 ですので、p1 の型も「『intの配列(要素数3)』を指すポインタ型」、つまり次のようにしてあげる必要があるわけです。 int (*p1)[3]; で、この場合 p1++ とするとどうなるのかといえば、array1[1][0] を指すポインタ (&array1[1][0]) になります。 これは次のように考えてみれば、ごくごく自然なことだとわかると思います。 まず、以下のように代入してみます。 p1 = array1; そうすると、以下の関係が成り立つことはわかると思います。 *p1[0] == *(p1 + 0)[0] == p1[0][0] == array1[0][0] また、以下の関係が成り立つのは良いでしょうか。 *(p1 + 1)[0] == p1[1][0] == array1[1][0] つまり、配列のインデックス操作は、実はこのようなポインタ演算を行っているだけ、というのが C の実態なのです。 ということは、p1++; した後は、以下のようになりますよね。 *p1[0] == array1[1][0] /* p1 は array1[1][0] を指すポインタになっている */ 少々長くなってしまいましたが、こんな説明でいかがでしょうか。

すると、全ての回答が全文表示されます。
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

> int array[2][2]={1,2,3,4}; > int *p; > のような場合、 > p=array;  > にするとエラーがでますが、なぜですか? エラーが出る理由のひとつは、他の方々が回答されているように型が異なるためです。 もうひとつの理由はC++だからです。Cの場合、型が異なるポインタを代入しても、警告が出ることはあってもエラーにはなりません。(エラーになるようなら、コンパイラのバグです)

すると、全ての回答が全文表示されます。
回答No.3

p=array; でなく、 p=array[0]; でしょう。 arrayには二つのポインタが存在する(ポインタの配列)のですから。 pは単なるポインタで、arrayはポインタの配列なんです。

すると、全ての回答が全文表示されます。
  • keroro001
  • ベストアンサー率23% (71/304)
回答No.2

すいません自信なし。 型が違うという話で済むのなら、私の話は冗長なので読まないで結構です。 arrayでは配列というオブジェクトのポインタをあらわす。 &array[0][0]では配列の指定した要素のポインタをあらわす。 型が違うのでコンパイルエラーになるのは#1の方の説明でお分かりになりましたか? 言語の仕様から言えば、int値のポインタに配列オブジェクトのポインタを入れることが出来ないのも当然です。 言語の仕様と、それをコンパイルリンクして、動作させてメモリに展開した時の仕様は混同されませんように。 これら2つの値(アドレス)が同一なのは、お使いのC言語のコンパイラ、リンカの仕様がそうだっただけ。 物理的なメモリの内容だけで判断してはいけません。 プログラムの方でどうにでもできてしまうのですから。 たとえば、char array[2][2];と宣言したときメモリが何バイト確保されるかはコンパイラ次第です。 先頭の何バイトかを制御用に使用して、要素の格納域がその後ろに続く場合、arrayと&array[0][0]のアドレスは異なってくることは理解できますか? コンパイルしたプログラムがどう動くかはC言語の仕様とは関係がないのです。

tattin894
質問者

補足

arrayで指したアドレスと &array[0][0]で指したアドレスは違うということですか? arrayでは制御用に確保されたメモリのアドレスを示して、&array[0][0]では、各要素用に確保されたメモリのアドレスの[0][0]の部分を示しているということ?

すると、全ての回答が全文表示されます。
noname#15691
noname#15691
回答No.1

>p=array;にするとエラーがでますが、なぜですか? 型が違うからです。 この場合、arrayは「int」のポインタではなく、「intの大きさ2の配列」のポインタになります。 ですから、 int (*p)[2]; とすると、 p = array; で、エラーは出ません。 もっとも、この場合、 p[0] p[1] p[2] p[3] ではなく、 p[0][0] p[0][1] p[1][0] p[1][1] となります。 >配列の場合array(&array[0][0])はこのメモリーの1が格納されているアドレスを指すわけですが、これをポインタpに入れるとなにか問題でも起こるんですか? 問題は起きませんが、「値は同じでも型が違う」ということをちゃんと押さえておいた方がいいと思います。

tattin894
質問者

補足

p=array;(これが正しいと考えると。)とすると僕の考えでは、 _(p[0][0])1_(p[0][1])2_(p[1][0])3_(p[1][1])4_ のようにメモリに並んでいて、 p++;とすれば、p[0][0]の位置からp[0][1]のアドレスを指すようになって、さらにもう一回p++;をすれば、p[0][1]からp[1][0]を指すよになるのではとおもったのですが、だめなのでしょうか?

すると、全ての回答が全文表示されます。

関連するQ&A