2016-04-22 2 views
1

私はこれをしばらく理解しようとしてきました。私は、ポインタはこのように宣言されて理解して何からポインタを使用する正しい方法は何ですか。そして、彼らはどのように実際に働くのですか?

:私が理解から

int x =1; 
int* p; 

は、pは現在、int型であるべきで指しているものは何でもPが、何も指されていないということです。意味をなさないそれは、その値に

p = &x 

を指し示すことができるように

次いで、PにXのアドレスを渡すと等しいどんなX今も* pおよびその逆に等しいです。

int x = 1; 
int* p = x; 

しかし、これは私を混乱さ:あなたはこのようにそれを行うだろうポインタを初期化したい場合は、ロジックの電車に続い

、。今私が理解していることは、pの値(それが指しているもの)はx、1の値ですが、xを実際に指していないということです。それではどうしますか? pは何も指していませんが、指されているものはどれも1ですか?わかりません。

私が知りたいもう一つのことは、pointer = pointerがどのように機能するかということでした。

のは、ロジックの私の電車と一緒に別の例を見てみましょう:

int x = 1; 
int* p; 
int* p2; 
p = &x; 
*p2 = *p; 

これは私に翻訳:P2で尖った値が値に等しいPで指摘したが、その変数を指していません。 pは(xである)を指し、xの値を指しています。

誰かが私にこれを明確にすることはできますか?論理の列車は間違っていますか?もしそうなら、私はそれをどのように見るべきですか?あなたはあなたが後者の混乱を見つけることが正しかった

int * p = &x; 

なく

int * p = x; 

を言うでしょうxへのポインタを取得する

int x = 1; 

+0

私はいくつかの段落でこのような質問に答えることはできないと思います。プログラミング、C言語、オペレーティングシステム、コンピュータアーキテクチャ、命令セットなどについての書籍を読むことに何週間も費やしてください。 –

+0

'int * p = x;'は動作しません。 'int * p =&x;'でなければなりません。一般的なルール - 左のものの "タイプ"は、右のものの "タイプ"と同じでなければなりません。これはポインタを含むものだけでなく、すべての代入と初期化に適用されます。 – fukanchik

+1

'int * p;'は整数へのポインタです。つまり、 'p'は整数のアドレス*を保持します。 'int * p = x;'を実行すると、 'x'の値を整数の*アドレス*に代入します。これは有効ではない可能性があります(' x'の値が1の場合、整数のアドレスは1で、おそらく有効ではありません)。これは 'int * p =&x;'でなければなりません。これは 'p'の値を変数' x'のアドレス*に割り当てることを意味します。 – lurker

答えて

2

重要なことに、コンピュータメモリには、整数またはポインタのバイトシーケンスはありません。これらのバイトをintまたはint*と解釈するのはあなたのプログラムです。 あなたのプログラムの外にちょうどバイトです

あなたの例を段階的に見てみましょう。

ステップ1:あなたが宣言して割り当てる変数

program: 
int x = 1; 
... 

は、あなたのコンパイラがすることを決めたと言う あなたは256バイトのメモリを持っており、あなたのint sが1バイトしかありデモンストレーション目的とし可変xためにメモリセル12を割り当てる:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |12:1| ... |255:X| 

ステップ2: あなたはポインタを宣言しているところ

変数 pのためのリコールステップ1 ...と、コンパイラ割り当てられたメモリセル5
program: 
int x = 1; 
int *p; 
... 

(ノート - pは5 Xあるセルの値ので、まだ初期化されていません!) :

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:X| .. |12:1| ... |255:X| 

ステップ3:あなたは、ポインタ

を割り当てる

リコールステップ2 ...セルpは、xへのポインタを格納します。

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12| .. |12:1| ... |255:X| 

ステップ4:あなたが第2のポインタを

program: 
int x = 1; 
int *p; 
p = &x; 
int *p2; 
... 

リコールを宣言している 我々はしたがって12 p(セル5)に格納され、セル12はxに割り当てられている知っていますステップ3 ...そして、あなたのコンパイラは、(値がXあるので、それはまだ割り当てられていないのです)変数p2ためのメモリセル6を割り当てた:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |255:X| 

ステップ5:(!まだ未定義の)あなたは第二を割り当てる指示先

program: 
int x = 1; 
int *p; 
p = &x; 
int *p2; 
*p2 = *p; 
... 

リコールステップ4、次いで*ppそうセル5であることをコンパイラリコールを行います実際の結果のアドレスとしてその値を使用します。セル12からの読み出しは、1を返します。コンパイラは、セル#6にp2という名前が与えられていることを知っています。p2は6です。 *p2は、p2の値を読み取って実際のストレージのアドレスとして使用する必要があることを意味します。しかし、私たちの場合、この値はX(未定義)です!しかし、実際のメモリチップには未定義の値はなく、ブート時に何かがそこに格納されています(例えば、値42)。仮想メモリが影響を受ける場合、状況はさらに複雑になりますが、ここでそれについて議論したくありません。だから、ブート時に電荷と宇宙線が42のランダムな値にこのセルを初期化したとしましょう。 *p2 = *pが実行されるときに何が起こるかを見てみましょう:*pが返された方法を見てきました。今、プログラムはそれをどこに保存するかを調べようとします。それは42を生成するp2の値を読み込みます、今のプログラムは、メモリセル421を格納すると結果が表示されます:現実の世界で

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:X| .. |12:1| ... |42:1| ... |255:X| 

をしかし、頻繁にクラッシュにつながる初期化されていない値を使用して。仮想メモリが関与すると、いくつかの領域のアドレス空間(256個のアドレス)にはメモリセルが割り当てられず、そのようなアドレスに書き込むとクラッシュする可能性があります。

ステップ6:あなたが第2のポインタを割り当て、それがxに再び指して定義させるされている

program: 
int x = 1; 
int *p; 
p = &x; 
int *p2; 
p2 = p; 
... 

リコールステップ4と、プログラムがクラッシュの原因となったステップ5を無視し...コンパイラは、どのセルがp(セル5)とp2(セル6)の両方に使用されているかを知っています。したがって、割り当てp2=pはこのように動作します。p(12)から値を取ってポインタとして解釈せず、代わりにp2にコピーしてください。今すぐp2x(セル12)へのポインタで初期化されます。

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:12| .. |12:1| ... |42:X| ... |255:X| 

ステップ7:

program: 
int x = 1; 
int *p; 
p = &x; 
int *p2; 
p2 = (int*)100; 
... 

...のは、この行に焦点を当ててみましょう:p2 = (int*)100;これは無名のを指すようにポインタを割り当てる方法を示しますが、名前の場所へのポインタを代入している メモリセル。コンパイラがまだセル#100に名前を割り当てていないことを思い出してください。しかし、この記憶場所に興味深いものがあることが分かっている場合、例えばコンピュータ装置がそのセルを介して私たちと通信している場合などはどうでしょうか?キーボードがメモリセル#100に次の文字を格納していて、それを読んでみたいとしたら?今、あなたは*p2としてそれを読むことができます:

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:100| .. |12:1| ... |42:X| ... |100:keyboard| ... |255:X| 

ステップ8:あなたは配列へのポインタの関係を明らかしている

program: 
int x = 1; 
int *p; 
p = &x; 
int a[5]; 
a[2]=18; 
int *p2 = a; 
p2[2]=3; 
... 

を...のは、この行に焦点を当ててみましょう:int a[5];:この宣言行は5つのセルを割り当てるようにコンパイラに指示し、そのセルにはaという名前を使用します。そして、コンパイラ細胞7、8、9、10、aのための11に割り当てられた:それはポインタ割り当てなかったこと

memory |address:value| (value of X means unknown): 
|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:X|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X| 

をノート - aは文字通り、他の変数のように使用されるでしょう!これはa[2]=18の仕組みです:最初のコンパイラはが開始され、7ということを知っていますので、その値を最初に使用してから2を追加して9を追加します。だから、ターゲットストレージセルが発見された - それは、細胞数9ですので、そのセルに18を格納します。

|0:X|1:X|2:X| ... |5:12|6:100|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X| 

それでは、どのようにint *p2 = a;作品を見てみましょう:コンパイラはこのため7時a開始7に格納されていることを知っていますp2もしアレイp2[2]=3;として使用することができ、ポインタを初期化した後

|0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:18|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X| 

(セル#6は、ステップ4でp2に割り当てられているリコール):これは*(p2 + 2) = 3の略です。 p2の値は7で、2を追加して9を与えるので、私たちは、セル#9に3を格納している:

|0:X|1:X|2:X| ... |5:12|6:7|7:X|8:X|9:3|10:X|11:X|12:1| ... |42:X| ... |100:keyboard| ... |255:X| 

iの値、変数、ポインタと配列の関係をカバーしようとしたような長い説明のために申し訳ありませんと最もこれらのユースケース

4

。 2番目の例では

、あなたは(変数xに含まれる値1、である)に事にpポイントを取り、どこp2ポイント、それを保存しようとします

*p2 = *p; 

を言います。残念ながらp2は初期化されておらず、有用な場所を指していないので、結果はあなたが望むものとなる可能性は低いです。だから、もしあなたが何をするのか混乱させるなら、あなたは混乱するのが正しいでしょう。

+0

しかし、' int * p =&x; 'は、pが指しているものがxのアドレスであることを意味していますか?値? – Delupara

+1

'int * p =&x'と書くと' int * '部分は' p'の型に過ぎません。 –

+0

@GarethMcCaughan「アドレスでの値」演算子「*」は、初期化時に同じ意味を持ちません。なぜなら、「* p = 3;」と書かれていれば、そのことを意味するからです。 – Delupara

0

ポインタは単純に整数であることを覚えておくと便利です。したがって、ポインタを作成すると、それは実際にはメモリ内のオフセット番号に過ぎません。ポインタのタイプは、ポインタが逆参照されたときにデータをどのように解釈するかをコンパイラに指示するだけです。あなたはこのような何かときに:

int *p = &x; 

をあなただけのxのメモリアドレス(オフセット)であるpに整数を割り当てています。ある意味では、すべてのポインタは実際に同じ「タイプ」を持ち、アーキテクチャーに応じて32ビットまたは64ビットの整数です。このようなポインタを逆参照:

int y = *p; 

ちょうど意味する「Pバイトによってメモリへのオフセット、および(4バイト)INTの形態であり私に値を与えます」。ポインタの型は、オフセットの後にメモリからデータを読み込む方法をコンパイラに指示するだけです。

+0

これは私が過去にmemの操作をしたことを考えるのに役立ちます。 – Delupara

+0

これに関する注意の非常に重要な言葉:Cでは、ポインタを含む算術演算を行うことができます。そのために、機械アドレスを表す整数として考えると、間違った答えが得られることがあります。どうして?例えば、 'p'が' 'int''へのポインタであれば' 'p''は' 'p''よりもメモリー上にある' 'int''を意味します。典型的なマシンでは' 'int 'は通常4バイトのサイズです。 (2バイトと8バイトは聞こえませんが) –

+0

同様に、 'p'と' q'が ''ポインタ ''と ''の間にある場合(厳密には、 malloc'ブロックのメモリ)、 'qp'はバイト単位ではなく' int'のサイズ単位で測定されます。だからあなたが 'int x [10];と言うならば。 p = &x[1];q = &x[3];であり、 'p'は0x23006Cであり、qは0x230074であり、q-pは2であり、8ではない。 –