質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.03%

p *p違いーポインタ

解決済

回答 7

投稿

  • 評価
  • クリップ 0
  • VIEW 1,464

score 257

intへのポインタ型
①でintへのポインタ型で変数pを定義する。
②でint型の変数xに20をいれる。
③変数pにxのアドレスをいれる。
④変数pの値を出力する
p と*pの明確な違いが分かりません。
どうやって理解すればいいでしょうか?
  int main()
{  
      int* p ;      ①
    int x=20;         ②
   p = &x;      ③
   printf("%d", *p);  ④
   return 0;
}
コード
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 7

+1

p : pに格納されているメモリ上のアドレスを示す
*p: pに格納されているメモリ上のアドレスに格納されている値を示す

あなたが 東京都千代田区1-1-1に住んでいるとすると

p→東京都千代田区 1-1-1
*p→あなた

という感じです

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 20:26

    解説ありがとうございます

    キャンセル

checkベストアンサー

0

以下の関係を知るには、コンピュータのメモリの扱いを知ることが不可欠だと思います。

p = *p


メモリは基本的に一次元の配列と同じです。
番地(アドレス)という形で、記憶領域(メモリ)は並んでいる順番に区画されています。
区画ごとの記憶容量は、基本的に1バイトです。

0x00番地からのメモリ内容が以下のようになっているとします。
(0x00 〜 0x07 の8バイトのメモリ内容を16進数表記しています。メモリ内容がすべて 0xFF になっているのは説明用だからです。実際はこの限りではありません。)

0x00: FF FF FF FF FF FF FF FF
0x08: FF FF FF FF FF FF FF FF
0x10: FF FF FF FF FF FF FF FF

仮にchar配列で 0x00番地からデータを定義した場合を考えます。

例1)
char cNum[] = {0,1,2,3,4};
//配置されるデータ:
//0x00: 00 01 02 03 04 FF FF FF

例2)
char cNum[] = "01234";
//配置されるデータ:
//0x00: 30 31 32 33 34 00 FF FF

例1の場合は、char配列に数値を格納しています。
{}の括りで配列に数値を収めた場合は、指定した値がそのまま配置されます。
ですので、0x00番地から5バイトの領域に 0x00〜0x04 が配置されます。

例2の場合は、char配列に文字列を格納しています。
文字列の場合は文字列データの最後に終端文字(0x0)が付されるので、実際のデータは {'0','1','2','3','4',0} と同じ意味を持つ記述になります。
従って、配置データの最後6バイト目に 0x0 がある事が分かります。(配置データは、文字列の表記より1バイト大きい。)


int型の場合は、コンピュータによってデータ幅が異なります。
最近のIntelCPUだと32bit幅が標準なので4バイトです。
(またIntel系のCPUはリトルエンディアンなので、メモリへは下位バイトから順に配置される点に注意。)

例3)
int num[] = {0,1,2,3,4};
//配置されるデータ:
//0x00: 00 00 00 00 01 00 00 00
//0x08: 02 00 00 00 03 00 00 00
//0x10: 04 00 00 00 FF FF FF FF

例4)
int num = 0x1234_5678;
//配置されるデータ:
//0x00: 78 56 34 12 FF FF FF FF


p = *p についてもう一度考えますが、説明の都合、変数と変数のポインタを別々の変数定義にしてみます。

int num1;
int num2;
int *pNum;

ここで num1 = 1; を行うと、メモリにはint値:0x0000_0001(32bit幅の数値:1)がセットされます。

0x??: 10 00 00 00 ..

仮に配置されるアドレスが 0x38 だった場合、pNum = # を実行すると pNum の値は 0x38になります。
(最近のCPUは32bitや64bit幅でのアドレス管理なので、実際にはもっと大きな数値が収まる。)

num2 = 0x10; を行うと、メモリにはint値:0x0000_0010(32bit幅の数値:0x10)がセットされます。
ここでnum2の配置されるアドレスが 0x3C だった場合、pNum = &num2; を実行すると pNum の値は 0x3Cになります。

この時のメモリの内容は以下の通りです。

0x38: 01 00 00 00
0x3C: 10 00 00 00

そして、この時 p = *p になる関係はどの変数になるかといえば、num2 = *pNum です。
pNum = 0x3C ですから、ポインタ:pNum のメモリにセットされた値は 0x10(=num2) です。

pNum = &num2; 直前だったらどうか。
pNum = 0x38 なので、num1 = *pNum です。pNumの指すアドレスの中身は 1(=num1)です。


具体的にメモリの配置をイメージする方が、多少は理解しやすいのではないかと思います。(何度も言いますが、動きを頭の中だけでトレースするのは大変なのでデバッガの利用がオススメです。)


違いですが、変数が値と1:1の関係であるのに対して、ポインタは1:nがあり得るところですかね。
プログラム中で利用する場合に変数の割り当て領域を覚えておくだけのものなので、別の変数にもなるワイルドカードみたいな扱いができます。

ちょっと違う視点で考えると、ポインタは「いろいろな種類の部品を取り付ける万能ジョイントの基本パーツ」です。型キャスト機能と併用すると異なるタイプの型も扱えるので、事実上なんでもポインタ経由で扱えるようになります。(それ故に闇の部分も濃いイメージが強いですが…)

その性質をどう利用するのか。という視点で見ると、いろいろ便利な実装が存在しますし、正直C言語にポインタがなかったら何ができるんだろう…というくらい、無いと幅が狭まってしまう機能です。

このあたりはC言語でいろいろプログラムを書いてみると有難味がわかってくるところだと思いますので、いっぱい実装を書くことが必要だと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 20:19

    丁寧な解説ありがとうございました。
    ポインタ奥深いですね、まだまだ勉強が足りないようです;;

    キャンセル

0

int* p;という書き方が良くないです。int *p;と書いた方が良い。これは「*pがintである」という宣言です。
pがポインタで、*pがint(pがポイントしているメモリに入っている整数値)です。

補足:
1行目に書いたのは、空白をどこに入れるかの問題では無く、宣言文がどういう意味を持っているかという話です。
〇「*pがintである」
×「pはint*である」・・・・「int*」という構文はありません

x = -y;を、x =- y;と書いて、「=-は符号反転して代入する演算子である」と主張すると変ですよね。空白の位置を変えても意味は変わらないし、今のCには=-という構文は無いし。
int*はintへのポインタを宣言する記法だ」はそれと同じくらい変です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 18:14

    回答文中の補足に書きましたが、コーディングスタイルの話じゃなくて、初心者向けにC言語の文法の意味の話として書いています。文法的な意味をちゃんと理解している人が、コーディングスタイルを定める・従うのは別にかまわないと思います。
    このあたりを、きちんと理解しておかないともっと複雑な型の理解で躓くと思いますので。

    キャンセル

  • 2015/09/03 19:06

    他人に説明する場合には、好みだけの話ではないと思います。

    例えば右寄せなら int *px, *py; と書けるものが、左寄せだと int* px, *py; とすべきなのか、int* px, * py; なのか、int* px; int* py; なのか、あるいはわざわざtypedef int* coord_ptr;とかするべきなのか、それらを説明(規定)しなければなりません。int* px, py; ではpyがポインタにならないことにも、初心者には一言必要でしょう。右寄せならその必要が無いので説明が楽です(*は識別子への修飾です、で済みます)。
    文法上どっちが良い悪いという話ではなく、単に右寄せの方が初心者には説明が簡単ですという話です。

    誰かのコーディング規約とか、えらい人がそうだから、ではなくて、初心者にまず必要なのは楽な方法だと思います。文法や構文を完全に分かった上でなら、完全に好みの話です。

    キャンセル

  • 2015/09/03 20:25

    なるほど、まず右寄せになれてみます。
    ありがとうございました。

    キャンセル

0

①でintへのポインタ型で変数pを定義する。
の文で「intへのポインタ型」が 「int*」で「変数」が「p」だと理解されているようですので、使い分ける時には

p : データが入っている入れ物を指す
*p : 入れ物の中に入っているデータを指す

とイメージしてみてはどうでしょうか。本来ならアドレスをからめて覚える方が正確に理解できると思いますが、とにかくイメージでもなんでも使い分けられるようにしていけば、だんだん理解できると思います。

ちなみに上記のイメージは私が仕事でC言語を最初に使ったときに先輩から教えてもらったものです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 20:24

    解説ありがとうございました、とても助かりました

    キャンセル

0

ためしに p を表示してみて
ください。

得体の知れない数字が
表示されると思いますが、
これは「変数xのアドレス」です。

*p は、p に格納されている
アドレスのメモリを参照する
という意味になります。

今、p には &x つまり x の
アドレスがセットされていますから、
*p は、x の値 20 を表示します。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 20:21

    解説ありがとうございました、やっと理解できました;;

    キャンセル

0

int *p はイント型ポインタです。
p = とすると p これに対して値を入れる、(アドレスが格納される)
*p = とすると *は覗き穴と覚えるとpの中身を見るてイメージですね。 *pは pの指すアドレスの中身です。

例文ですと 
p = &x  // p → x pはxを指す
print(*p)  //  *は覗き穴だと考えてください   p→x を指してるので p → x = 20 となっております
// pの中身は 覗き穴(*)p *p = 20

  p →  x
  *p       ||
     ↘    ||
           20
図にするとこんな感じですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 20:19

    のぞきあな、覚えやすい考え型ですね。
    参考にさせてもらいます、ありがとうございました

    キャンセル

-1

④変数pの値を出力する 
printf("%d", *p);

よく見て下さい。本当に変数pの値を出力するなら、
printf("%d", p);
であるはずです。
ここでの*は間接演算子で、
*pと書けば、pの値(メモリ番地)に格納されている値を返します。

つまり④は
変数pが指す先の値(=*p)を出力する 
です。

過去にも似たような質問があり、
ベストアンサーがとても分かりやすい説明だったので
参考にして下さい。


Cは紛らわしいことに*の意味が3つあります。
1.乗算a * b;
2.ポインタ型の宣言int* x;,int *x;
3.間接参照c = *p;

宣言ですが
int* xと書けば、xがintのポインタ型と言う意図を表わせ、
int *xと書けば、*xがint型と言う意図を表せます。
処理は一緒なので、しっくり来る方を使うといいです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/09/03 20:21

    ポインタ型の宣言と間接参照で混乱していたみたいです。
    分かりやすい解説ありがとうございました

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る