dポイントプレゼントキャンペーン実施中!

c[ ] = { 1,2,3,4,5 };
p = c
の場合
▽1 *p++ と、
▽2 (*p)++ に違いがあるのかどうか、違いがあればその内容について、どなたか、ご解説をしていただけないでしょうか?

何となく、下記のような気がするのですが、この考え方であっているのでしょうか?
▽1 *p++ の場合は、*(p+1) で、ポインタ位置をずらしている
▽2 (*p)++ の場合は、*p = *p+1 で、pの値を変更している

A 回答 (7件)

ポインタは、初心者が最もつまづきやすい部分だと言われています。


実際、おそらくポインタでつまづく人は多いのかも知れません。
しかし、ポインタというものは、慣れた人に言わせれば
「今になってみるとどうして悩んでいたのか分からないほどシンプルな機能」
なのだそうです。気楽にいきましょう。


(1)

C言語を扱うには、ハードウェアまわりの理解が少しばかり必要です。
ポインタについては、

1. メモリのこと
2. コンパイルして作った機械語のプログラムが実際に動くときのこと

を考えてください。

1. 変数を扱うためには、変数の内容を保存するためにメモリ内の領域を確保する必要があります。
2. メモリの領域は、1バイトごとのアドレスで管理されています。
3. マシンは複数のプログラムが共有するため、変数のアドレスは実行するたびに変わります。


(2)

変数とは何でしょうか。
変わる数と書いて変数です。マシンの中では音も絵も1と0の列ですから、数です。

実行するたびに変わる可能性があるものを一時的に記憶しておくためのものが変数です。
実行時に変数のために確保される領域のアドレスは毎回変わるので、アドレスを記憶する変数というものがあります。
それがポインタです。


(3)

/* サンプルプログラム */

#include<stdio.h>

int main(void)
{
char a; //char型の変数aを作成
char *pt_a; //charのポインタ型の変数pt_aを作成

a = 'A'; //変数aに割り当てられたメモリ領域に'A'を書き込む
pt_a = &a; //pt_aに割り当てられたメモリ領域に「変数aに割り当てられたメモリ領域の先頭のアドレス」を書き込む
(*pt_a)++; //pt_aの内容が指し示すメモリ領域に「そこにあるデータに1を加算したもの」を書き込む
*pt_a++;

/* 実行時のメモリの状態を出力 */
printf("char型変数 a の 中身: %c\n", a);
printf("char型変数 a の アドレス: %p\n", &a);
printf("\n");
printf("charのポインタ型変数 pt_a の 中身: %p\n", pt_a);
printf("charのポインタ型変数 pt_a の アドレス: %p\n", &pt_a);

return 0;
}

コンパイルして、実行してみましょう。


(4)

/* 余談 */
charの表現に必要なデータ長は1バイトですが、intになると、これが2バイトとか4バイト(コンパイラによって異なる)だったりします。

変数の型によって使用するメモリの領域の幅が異なるので、
「変数が利用する領域の先頭のアドレス」だけではデータを操作できません。
なので、ポインタにはアドレス以外にもう一つ、「領域の幅」という情報がくっついてきます。
但し、これはコンパイラ的にはソースコードを読むだけで判断でき、実行するたびに変わるというものではないため
直接的にポインタ変数の実体に含まれることはありません。
しかしながら、どこか別の場所で確実に「幅」が管理されているという事は、覚えておくと便利なことがあるかもしれません。

この回答への補足

t11uさん、ご回答ありがとうございます。

(3)の
(*pt_a)++; //pt_aの内容が指し示すメモリ領域に「そこにあるデータに1を加算したもの」を書き込む
までは、理解することができました。

が、次の、
*pt_a++;
はどんな意味合いになるのでしょうか?

何となく、そこにあるアドレスから指定したデータ型の分(幅?)だけ、移動するみたいなイメージではないのか? と思うのですが、そうだとすればどうしてそうなるのか、よく分かりません。( )があるとないとで、どうして上記と違うのか? など…。

あまりしつこいのもアレですので、理解するのは諦めて、
もう、そうなるもの、と暗記した方がよい感じでしょうか?

うーん、私には難しすぎる……。

補足日時:2008/09/28 08:00
    • good
    • 0

こんにちは。


回答の方はすでに出されていますので別の見解から...

ポインタはC言語の肝の部分でポインタだけで一冊本が出来る位重要な部分です。
ですのでポインタ専門の本を読むことをお勧めします。
でないとポインタ関連(ポインタ配列、ポインタのポインタ等)で困ると思います。

私の場合、「秘伝 C言語問答 ポインタ編」でポインタを理解しました。

ご参考までに。

この回答への補足

yuji_syamiさん、アドバイスありがとうございます。

明日、本屋を覗いてみます。

補足日時:2008/09/09 18:42
    • good
    • 0

> ▽1 *p++ の場合は、*(p+1) で、ポインタ位置をずらしている



p++ を評価した後の p と、p+1 を評価した後の p とが
異なることは理解できますか?

この回答への補足

asuncionさん、ご回答ありがとうございます。

p++ を評価した後の p と、p+1 を評価した後の p の違いが理解できません。
p++もp+1と同じような気がするのですが…。

補足日時:2008/09/09 18:52
    • good
    • 0

▽1 *p++ の場合は、*(p+1) で、ポインタ位置をずらしている


ポインタ位置をずらしているのはあっています。
▽2 (*p)++ の場合は、*p = *p+1 で、pの値を変更している
*p = *p+1はあっていますが変更しているのはpの値ではなく*pの値ですね。
c[0]が2になっているのが確認できるはずです。

この回答への補足

php504さん、ご回答ありがとうございます。

「変更しているのはpの値ではなく*pの値ですね。」
の意味が理解できなかったのですが、
pの値と*pの値は違うのでしょうか?

補足日時:2008/09/09 18:55
    • good
    • 0

このような疑問は、コンパイラに聞いてみると一目瞭然です。


コンパイルすると次のようになります。

int *p;  //sizeof( int ) = 4

*p++
  mov  edx, DWORD PTR _p
  add  edx, 4
  mov  DWORD PTR _p, edx

(*p)++
  mov  eax, DWORD PTR _p
  mov  ecx, DWORD PTR [eax]
  add  ecx, 1
  mov  edx, DWORD PTR _p
  mov  DWORD PTR [edx], ecx

この回答への補足

yphkz4063さん、ご回答ありがとうございます。

add  edx, が違うというのは分かったのですが、
これは、何を意味しているのでしょうか?

補足日時:2008/09/09 18:59
    • good
    • 0

ポインタを覚える前の基本的なことですけど、インクリメントの・・・


int a=0,b;
while(b<10){
b= ++a; /* プレインクリメント */
printf("a=%d, b=%d\n",a,b);
}
と・・・
int a=0,b;
while(b<10){
b= a++; /* ポストインクリメント */
printf("a=%d, b=%d\n",a,b);
};
の違いについて、理解できていますでしょうか?

この回答への補足

maimi09さん、ご回答ありがとうございます。

両者の違いについては、理解できているつもりです。

前者は画面表示する前にインクリメント
後者は画面表示した後にインクリメント

で、ok?

補足日時:2008/09/09 18:37
    • good
    • 0

>▽1 *p++ の場合は、*(p+1) で、


いいえ。両者は同じ意味ではありません。

▽2 (*p)++ の場合は、*p = *p+1 で、pの値を変更している
いいえ。p の値は変更されません。

この回答への補足

koko_u_さん、ご回答ありがとうございます。

「いいえ。両者は同じ意味ではありません。」
についてですが、具体的に、どこが異なっているのでしょうか?

「いいえ。p の値は変更されません。」
についてですが、pの値と*pの値は異なるのでしょうか?

補足日時:2008/09/09 19:02
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!