1

私はHSWでこのプログラムに出くわしました:

int *p;
int i;

p = (int *)malloc(sizeof(int[10]));
for (i=0; i<10; i++)
    *(p+i) = 0;
free(p);

ループを完全には理解していません。pメモリがバイトアドレス可能であり、各整数が4バイトのメモリを使用し、アドレス0からへのポインタに40バイトのメモリを割り当てると仮定します39
さて、私が理解していることから、ポインタpには最初に値0、つまり最初のメモリ位置のアドレスが含まれています。ループでは、後続の整数にアクセスするために変位がポインタに追加されます。

39変位値が。だけの場合、メモリアドレスがどのようにアクセスされるのか理解できません0 to 9。確認したところ、ポインターが4の倍数でインクリメントされていることがわかりました。これはどのように発生しますか?整数型のポインタが原因だと思います。各ポインタは、データ型のサイズだけインクリメントされると思われます。これは本当ですか?

しかし、整数ポインタを使用して実際にメモリ位置2をポイントしたい場合はどうなりますか。だから、私はこれを行います:p = 2。次に、このポインターを逆参照しようとすると、セグメンテーション違反が発生する可能性がありますか?

4

5 に答える 5

2

さて、私が理解していることから、ポインタpには最初に値0が含まれています

いいえ、10の配列の最初の整数へのアドレスが含まれています(mallocが成功したと仮定します)。

ループでは、後続の整数にアクセスするために変位がポインタに追加されます。

うーん、いや。あなたが何を意味するのかわかりませんが、それはコードが行うことではありません。

確認したところ、ポインターが4の倍数でインクリメントされていることがわかりました。これはどのように発生しますか?

ポインタに+-++-etc演算子を使用するポインタ演算は、型を知るのに十分賢いです。intポインタとwritep++がある場合、pに格納されているアドレスはsizeof(int)バイト単位で増加します。

しかし、整数ポインタを使用して実際にメモリ位置2をポイントしたい場合はどうなりますか。だから、私はこれを行います:p=2。

いいえ、そうしないでください、それは意味がありません。メモリ内のアドレス0x00000002を指すようにポインタを設定します。


コードの説明:

int *p;整数へのポインタです。書くことによって、 pが指す内容*p = somethingを変更します。書くことによって、pが指す場所のアドレスを変更します。p = something

p = (int *)malloc(sizeof(int[10]));混乱したプログラマーによって書かれました。mallocの結果をキャストすることは意味がありません。このサイトで、そのトピックに関する広範な情報を見つけることができます。

書くsizeof(int[10])ことは書くことと同じ10*sizeof(int)です。

*(p+i) = 0;書くこととまったく同じですp[i] = 0;

次のようにコードを修正します。

int *p = malloc(sizeof(int[10]));
if(p == NULL) { /* error handling */ }

for (int i=0; i<10; i++)
{
  p[i] = 0;
}

free(p);
于 2013-02-26T13:53:04.100 に答える
2

型付きポインタがあるため、一般的な操作(加算または減算)を実行すると、型の配置が自動的に調整されます。sizeof (int)ここでは4、コンピュータ上にあるのでp + i、アドレスp + sizeof (int) * i、またはp + 4*iあなたの場合になります。

そして、あなたはその声明を誤解しているようです*(p+i) = 0。このステートメントは。と同等p[i] = 0です。明らかに、あなたが要求したメモリを実際に割り当てることができない場合を除いて、あなたのmalloc()呼び出しはあなたを返しません。0

次に、最後の質問は、「mallocされたアドレスを正確に2バイトシフトすると、どうなるか」という意味だと思います。

答えは、次に何をするか、およびシステムのエンディアンに依存します。例えば:

/*
 * Suppose our pointer p is well declared
 * And points towards a zeroed 40 bytes area.
 * (here, I assume sizeof (int) = 4)
 */

int *p1 = (int *)((char *)p + 2);
*p1 = 0x01020304;
printf("p[0] = %x, p[1] = %x.\n", p[0], p[1]);

出力します

p [0] = 102、p [1]=3040000。

ビッグエンディアンシステムでは、

p [0] = 3040000、p [1] = 102

リトルエンディアンシステム。

編集:コメントに答えるために、ランダムに割り当てられたポインターを逆参照しようとすると、次のようになります。

  • あなたは幸運です:あなたがタイプするアドレスはあなたのプログラムに割り当てられたメモリ領域に対応します。したがって、これは有効な仮想アドレスです。セグメンテーション違反は発生しませんが、変更すると、プログラムの動作が損なわれる可能性があります(確かに...)
  • あなたは幸運です:アドレスが無効です、あなたはあなたのプログラムが物事を完全に台無しにするのを防ぐ素晴らしいセグメンテーション違反を取得します。
于 2013-02-26T13:38:50.697 に答える
2

さて、私が理解していることから、ポインタpには最初に値0が含まれています

いいえ、正常に戻った場合、ポインタpは値を保持しません。0malloc

宣言した時点では、ポインタは初期化されておらず、おそらくガベージ値を保持しています。によって返されるポインタに割り当てると、ポインタはmalloc、アロケータが占有されていないと見なす動的に割り当てられたメモリの領域を指します。

変位値が0から9の場合、39までのメモリアドレスにアクセスする方法がわかりません。

実際の変位値は0, 4, 8, 12 ... 36です。ポインタpには型があるため、その場合int *、これは、ポインタ演算で適用されるオフセットがsizeof(int)、あなたの場合はであることを示します4。つまり、変位乗数は常に、ポインターが指すタイプのサイズに基づいています。

しかし、整数ポインタを使用して実際にメモリ位置2をポイントしたい場合はどうなりますか。したがって、これを行います:p =2。次に、このポインターの参照を解除しようとすると、セグメンテーション違反が発生する可能性がありますか?

2その部分はオペレーティングシステムによって予約されるか、別の形式で保護されるため、プロセスのアドレス空間では正確な場所が利用できない可能性があります。その意味で、そうです、セグメンテーション違反が発生します。

ただし、サイズで均等に分割できない場所でデータ型にアクセスする場合の一般的な問題は、配置要件に違反することです。多くのアーキテクチャでは、intは4バイト境界でアクセスされると主張します。その場合、コードは、技術的に未定義の動作である非整列メモリアクセスをトリガーします。

于 2013-02-26T13:40:48.840 に答える
1

これはポインタ演算と呼ばれます。nタイプのポインタに整数を追加すると、ポインタが要素t*ごとに移動します。n * sizeof(t)したがって、sizeof(int)が4バイトの場合:

p + 1 (C) == p + 1 * sizeof(int) == p + 1 * 4 == p + 4

次に、配列のインデックスを作成する方が簡単です。

*(p+i)配列のi番目の整数pです。

于 2013-02-26T13:39:48.310 に答える
0

2「メモリ位置2」がメモリアドレスの例を意味するのか、配列の2番目の値を意味するのかはわかりません。2番目の値を意味する場合、それはメモリアドレスになります1。この場所へのポインタを取得するには、int *ptr = &p[1];または同等int *ptr = p + 1;に、この値を。で出力できますprintf("%d\n", *ptr);。メモリアドレス2(サンプルアドレス)を意味する場合、それは配列の3番目の値になり、p[2]またはが必要になりますp + 2。メモリアドレスは通常16進数であり、実際には0から始まらないことに注意してください。これは。のようになります0x092ef000, 0x092ef004, 0x092ef008, . . .。他のすべての答えは、メモリアドレスを使用していることを理解していません0 . . . 39例のアドレスと同じように。私はあなたが正直にアドレス0x00000000で始まる物理的な場所を参照しているとは思わない、そしてあなたがそうなら他の誰もが言っていることは正しい。

于 2016-04-18T07:17:53.510 に答える