• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:C言語、配列とポインタとアスタリスクの関係)

C言語の配列とポインタの関係について疑問があります

このQ&Aのポイント
  • C言語の配列とポインタの関係について疑問があります。配列の宣言とポインタの宣言はどう違うのか、アスタリスクの意味とは何か、printfでの表示方法について知りたいです。
  • C言語の配列とポインタについて疑問があります。特に、配列とポインタ変数の宣言の違いや、アスタリスクの役割について詳しく教えていただきたいです。
  • C言語の配列とポインタに関して疑問があります。特に、配列の宣言方法とポインタの宣言方法の違いや、printfでのアドレスと値の表示方法についてわかりやすく説明していただけると嬉しいです。

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

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

C言語では、配列とポインタが密接な関係にあります。 double *p ; int n ; としたときに *(p+n) と p[n] は同じものを指します。 (ポインタpから数えてn番目のアドレスにある、double型) *p = *(p+0) = p[0] です。 なお、同様に double a[MAX] ; int n ; としたときに a[n] と *(a+n) は同じものを指します。 a[0] = *(a+0) = *a です。 > ポインタ変数は、プログラムの文中で通常の変数として使うときには「*heap」のように先頭にアスタリスクを付けなければならかなったと記憶しています * 演算子を付けるかどうかは、やりたいことが何か、と、操作しようとしている値の型は何か、と考えて使うようにしましょう。 ポインタだから*、と単純に考えないことです。 > *heap[5] こに括弧を付けるすると、演算子の優先順位から[]の方が強いため *(heap[5]) となります。 heap[5] = *(heap+5) より、int型となり、ポインタの演算*が使えないことがわかります。 > アドレスを表すか、そのアドレスに格納された値を表すかを切り替えるには、単にその変数を受ける「%d」や「%p」を変えるだけ、ということになるのだと思います。 これは、printf(や同系統の関数)の仕様の話になります。 printfでは、引数の型は調べていません。なので「アドレスを表すか、そのアドレスに格納された値を表すか」ということは関係ありません。 heap[5] の値がそのまま渡されます。 これを、書式文字列に従って取り出すだけです。 %dだったらsizeof(int)だけメモリから順番に読み出し、intとして解釈した値を出力します。 %pだったらsizeof(void *)だけメモリから順番に読み出し、ポインタとして解釈した値を出力します。 今回は同じ5という値を出力しているように見えます。が、これはたまたまであって、他の場合に同じようになるとは限りません。

tuktukrace
質問者

お礼

ありがとうございます。 お礼が遅れましたが、回答はすぐに見ておりました。 試しに、次のように書いてみました。 int array[3] = {5,6,7}; printf("%d\n",*(array +1)); printf("%d\n",array[1]); すると、結果は同じ「6」になりました! 配列の変数は、単体では最初の配列のアドレスで、[]の添字でそれをずらしていたんですね。 そうなってくると、別の回答でも指摘された「ポインタ変数の配列」という解釈そのものがそもそもおかしいと言うことがわかりました。 > *(heap[5]) > となります。 > heap[5] = *(heap+5) より、int型となり、ポインタの演算*が使えないことがわかります。 この部分、納得しました! レベルに合わせて順序立てて説明してくださりありがとうございました!

その他の回答 (2)

  • hashioogi
  • ベストアンサー率25% (102/404)
回答No.3

int *heap ; はポインタが入る入れ物です。大きさはsizeof (int*)で大した大きさではありません。メモリアドレスが1つ入る分だけの大きさです。したがってあなたが考えているような、複数のポインタをここに入れるのは無理があります。 heap = (int *)malloc(sizeof(int) * 10); でmallocはどこにあるかユーザーはわからないけどヒープという大きな領域から連続したsizeof(int) * 10バイトの領域を切り出してあなたに提供してくれました。mallocはあなたがint型のデータを複数格納するために使用するとかは知りません。とにかくあなたに言われたバイト数の領域を単に切り出しただけです。 そしてmallocの戻り値は「ポインタ変数(の配列)」ではなく切り出したsizeof(int) * 10バイトの領域の先頭アドレス1つです。切り出した領域は型の色がついている訳ではありませんのでどのように使おうと勝手なのですが、あなたはint型の配列用に使うために(int*)でキャストしてheapに格納してます。 得られた領域はint型のデータが10個分格納できる大きさです。5番目をアクセスしたければ heap [5] とします。

tuktukrace
質問者

お礼

ありがとうございます。 >ポインタが入る入れ物です。大きさはsizeof (int*)で大した大きさではありません。 ここですね。たしかに、おっしゃるとおりです。宣言だけを見れば、ポインタのアドレスだけが入る変数ですが、mallocを見ていたら、なんだか配列が入るのではという気がしていました。 mallocの戻り値は、指定された範囲の先頭のアドレス、というだけですね。ヒープという文脈で共起表現のように出てくる「確保」という言葉からなんとなくイメージだけはあったのですが、mallocはまさに「確保」してくれて、その先頭アドレスを教えてくれるだけなんですね。きっと、確保された領域はほかの変数やら何やらで侵されないようなしくみがあるのだと推察します。そう考えるといろいろのことに合点がいきます。 また一歩、レベルアップした気がします!

回答No.2

int *heap; int i; があるとき、 heap[i] と *(heap+i) は等価です。 したがって > 1:printf("%p\n",*heap[5]); //エラー これが "heap[5] のアドレス" を printしたかったのであれば &heap[5] または heap+5 が正解。

tuktukrace
質問者

お礼

ありがとうございます。 試みに、次のように書いて実行してみました。 int array[3] = {5,6,7}; printf("%p\n",&*(array +1)); printf("%p\n",&(*(array +1))); printf("%p\n",&array[1]); printf("%p\n",&(array[1])); (ひょっとしたら一部、本当はエラーになるものが含まれているかもしれませんが) 私のコンパイラでは、すべて同一のアドレスが返されました。 配列というのは、[]を使ってポインタの仕組みを利用して配列を実現しているようですが、配列の中の個々の変数自体は、やっぱり普通の変数として機能しているのですね。だからこそ、&をつけてアドレスが出るのですね 大変勉強になりました。