- ベストアンサー
ポインタの理解についての疑問
- Cの絵本で紹介されているプログラムについて質問です。
- 12行目の"%d番目で発見しました。"の部分でp - sを使っていますが、その意味がわかりません。
- ポインタの理解に困っているので、参考書以外で教えていただけると助かります。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
ポインタは好きなように前後に移動させたり、まったく違った値を代入したり出来ます。 今回の場合はchar形なので理解しやすいと思いますが、 最初にs=0x87654321だったと仮定しましょう。 6行目でp=sとしているので、この時点ではp=0x87654321です。 15行目のループの中でポインタを1つ加算しています。char形なので、最初の1順目でp=0x87654322となります。(この時点で*pは最初の文字の"I"から" "(スペース)に変わります。) ですから、*pはループするごとに"I", " ", "l", "o", ...となり、p-sは0,1,2,3,...となります。
その他の回答 (3)
- ency
- ベストアンサー率39% (93/238)
ポインタ演算って、なんかパッと見わかりにくいので、私だったら、こんなふうに書くかなぁ。 ------------------------------------------------ #include <stdio.h> main() { char s[] = "I love cat and dog."; char c = 'a'; char *p = s; int n = 0; /* 追加 */ int i = 0; printf("\"%s\"の中から\'%c\'をさがします。\n", s, c); /* *p の代わりに p[i] を参照する */ while(p[i] != '\0') { if(p[i] == c) { /* 結局はインデックス i を参照しているだけ */ printf("%d番目で発見しました。\n", i + 1); ++n; } /* ポインタ p のインクリメントの代わりに インデックス i をインクリメント */ ++i; } if(n == 0) { printf("1つも見つかりませんでした。\n"); } else printf("全部で%d個見つかりました。\n", n); return 0; } ------------------------------------------------ ++p しながら *p を参照している箇所を ++i して p[i] を参照するようにしてみました。 そうすると、「p - s」はインデックス「i」と同じことになりますよね。 このようなことが可能なのは、C言語では配列をその先頭要素へのポインタに読み替えてしまうからです。 配列要素 a[i] → *( a + i ) 配列要素 a[0] → *( a + 0 ) ⇒ *a 配列要素へのポインタ &a[i] → a + i 配列要素へのポインタ &a[0] → a + 0 ⇒ a この読み替えは機械的に行われますので、ポインタ p についても同様の標記が可能になるわけです。 p[i] → *( p + i ) &p[i] → p + i *( p + i ) と書けるところは、p[i] と書いてしまっても問題ないわけです。 # ポインタのインデックス標記には賛否両論あるようなので # このへんで留めておきます。 あ、逆に混乱させてしまったら、申し訳ありません。 「こんな説明もあります」という程度に考えてください。 [追伸] No3 chie65536 さんの「&a[n]-&a[m] = n-m」の説明は見事だと思いました。
- chie65536
- ベストアンサー率41% (2512/6032)
>ポインタって言うのは、アドレスを格納する変数ですよね? この解釈は、間違ってはいませんが、正しくもありません。 ポインタとは「任意のデータ型の、要素(実体)が格納された位置」の事です。 ポインタ変数とは、それを格納する変数の事です。 ここで重要なのは「ポインタ」を「アドレス」と捉えず「要素の位置」と捉える事です。 「sを指すポインタ」は「&s[0]を指す、つまり、配列sの0番目の要素の位置を指す」と理解するのが重要なのです。 さらに「文字列とは、最後の要素が\0になっているcharの配列」と理解していると判りやすいでしょう。 さて、ポインタ変数pがsを指している時、つまり、&s[0]を指している時、++pを実行すると、pは&s[1]になります。 「ポインタをnだけ加算すると、n個分うしろの要素を指す」のを理解して下さい。 ここで、新たな「お約束」が出て来ます。それは「ポインタ同士を引き算すると、それぞれのポインタが指す要素番号を引き算した結果になる」と言うお約束です。 簡単に言うと、式「(&s[n])-(&s[m])」は「n-m」を返す、と言う事です。 最初、p=sだった状態からpが4つ(つまり5文字目に)進み「&s[4]」を指している時「p - s + 1」を計算すると「&s[4] - &s[0] + 1」を計算する事になります。つまり「4 - 0 + 1」を計算します。とうぜん、この結果は「5」になります。 同じ位置を指すポインタ同士を引き算すればゼロに、ポインタが指す位置の前後が逆ならポインタ同士の引き算の答えはマイナスになります。
お礼
yosi_yosi さん nagare さん chie65536 さん 3人の方々ありがとうございました!! 3人の方共にすごくわかりやすい説明でした!! やっと理解できました。 また、printf()の中の*pとpの違いもわからなかったのですが、これはネットで見つかり理解できました。 *Pは内容。pはアドレスらしいですね。 本当にありがとうございました。 それに、chie65536 さんの「お約束」のことは参考書に載ってなく、貴重でした。 違う参考書もあたってみたほうがいいですか?参考書によって。そういったことが載っている本や載っていな本があるんでしょうか? わかりやすい説明本当にありがとうございました。
- nagare
- ベストアンサー率33% (280/831)
p - s + 1 を p - &s[0] + 1 と書き直したら分かりますか? (sは&s[0]です) pですが++pでカウントアップしてますよね 最初pは&s[0]ですが++pで&s[1]となります "l"でHITした場合Pは+2しますので &s[2]-&s[0]となるわけです わかりますか? charのポイントは1UP longのポイントは4UP というのを理解すると便利ですよ
お礼
encyさんお返事遅くなりました。 ありがとうございました。 わかりにくいなんてないですよ。 encyさんの説明もわかりやすかったです。 書店に行ってもポインタだけの本があったりして、ポインタって難しそうですね。でも、ポインタは良く使うとのことなんで、覚えないと・・・・。 ありがとうございました。