C言語のポインタを理解したいと思っています
&と*が理解できていません。
&を変数につけると番地が取得でき、
*を変数につけて、別の変数の番地を格納すると、エイリアスとなるという
認識です。
&と*を付けた場合でそれぞれの挙動を上記で試してみました。
21行目と22行目の結果は、
変数に*をつけるとエイリアスになるという理解なので、
iが+1されるというのは理解できるのですが、
16行目と17行目の結果がなぜそうなるのかよくわかっていません。
教えてほしいです。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
q は6行目の代入時にiの番地ではなくiの値(5)を番地として代入しています。
ですので、qは値が5になっており、ポインタに対して+1するとC言語の決まりで型のサイズ分足されるので、
int型のサイズは4(環境によります)で5+4=9となります。
これと同じ理由で、s+1はiの番地の4バイト後ろを示しますが、番地を符号ありの整数として扱っているので4足すと-2106799988 + 4 = -2106799984 となります。
int* はエイリアスというよりも「int型の変数がある番地が入っている値」と覚えた方がいいと思います。
投稿2017/05/27 05:13
編集2017/05/27 05:32総合スコア2850
0
こんにちは。
えっと、まず5行目と6行目の定義は誤りです。警告は出なかったでしょうか?
間違っているので説明が難しいのですが、良くある間違いでもあるので説明してみます。
int i=5;
int p=&i;
pは整数型です。4バイトであることは比較的多いですが、必ずしも4バイトではありません。
&iは変数iが格納されているアドレスですね。アドレスは32ビット環境では4バイトです。(32ビット=4バイトなので) しかし、64ビット環境では8バイトです。
4バイトの記憶領域を持つ変数は、8バイトの値を記録することはできませんね。
ですので、環境によっては意図通り動作しないコードなので「誤り」なのです。
ただし、32ビット環境がメジャーだった期間は長かったです。Windows 95からここ2~3年前までくらいなので20年近く続いてますね。このケースではint p=&i;と記述しても意図通り動作するため、この誤りが結構広まっています。
int *q=i;
は、その逆ですね。qはint型変数へのポインタです。ポインタの方がint型より大きい処理系がほとんどなので意図通りに動作する場合が少なくないとは思いますが、qはポインタですから、NULL、もしくは、何か適切なメモリのあるアドレスを指すのが妥当です。
そこに5と言う決め打ちの値をアドレスとして入れてます。5番地に何が入っているのかは、OSによって異なりますし、アプリの起動ごとに変わるかもしれません。
そのようなメモリかどうか分からない謎の領域を指すポインタは不正なのです。
ですので、意味が可笑しい16行目の説明は割愛します。
なお、17行目と動作自体は同じです。
C言語のポインタは配列を指すこともあります。と言うか配列名は配列先頭へのポインタでもあるように、ポインタが配列を指すことは非常に多いです。
なので、+1することで次の要素を指すようにすると都合が良いため、C言語規格で+1は次の要素を指すと決められています。
従って、ポインタに1加えると多くの処理系ではint型のバイト数分値が増えます。(アドレスがバイト単位では無いようなCPUもあるので、そのようなCPUでは必ずしもバイト数分増えるとは限らないですが。)
お使いの処理系はアドレスがバイト単位であり、かつ、int型が4バイトと思います。なので、l12で出力したSのアドレス-210679988に対して、l17では4を加えて-210679984となっています。
投稿2017/05/27 05:28
総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
本題に対する回答はあるので,別の観点から補足します。
&を変数につけると番地が取得でき、
*を変数につけて、別の変数の番地を格納すると、エイリアスとなるという
認識です。
C言語は,&
はまだしも,*
がかなり使われる場所によって意味が変わってくるので,正しく把握することが重要です。
ポインタ - C言語構造体のtmpを使ったソート方法(52359)|teratail
**【左辺にあるとき】 **
pt + j
: そもそも左辺にこれない
*(pt + j)
: pt + j
の演算結果の値に対応する番地
**【右辺にあるとき】 **
pt + j
: pt + j
の演算結果の値
*(pt + j)
: pt + j
の演算結果の値に対応する番地にある値
↑に追記しますが,変数宣言部に*
があるときは,それをポインタ変数として宣言します。ここで同時に代入を行うときは,代入すべき内容は番地です。宣言部の*
は「値を番地として評価する」ということは行いません。
また,一部未定義の動作が含まれているので挙げておくと
int
型変数の番地は必ずint *
型の変数に代入するint *
型の表示フォーマットには必ず%p
を利用する
実際に何か書く時にはこれを守ってください。番地がint
であるとは限らないので。
(実際uint64_t
とかunsigned long long int
のほうが適切な気がする)
投稿2017/05/27 05:29
総合スコア5223
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/05/27 14:32
2017/05/27 18:00