0

次のcコードを使用して、ランダムなメモリ位置で値を読み取ろうとしています

 main()
 {
   int a,*b;
   printf("enter the value of a");
   scanf("%d",&a);
   b=a;
   printf("%d\n%d\n",a,*b);
   getch(); 
  }

しかし、変数の代わりにsomenegative valuesまたは whenが入力された場合でも、プログラムはクラッシュします。私が間違っていることは何ですか?ポインターに負の値はありませんか?zeroascanf

4

6 に答える 6

3

問題は、おそらく最新のフルサービスのオペレーティング システムで実行していて、ほとんどの C プログラミング入門書で説明されているものよりも複雑な抽象マシンを提供しているということです。

特に、任意のアドレスへのアクセスには OS による制限があります。スタックとデータセグメントを使用する権限があり、ヒープの一部にアクセスする権限があることを確認するのは関数ファミリーであるため、標準変数に関連付けられたアドレスを見てもこれに気付かないalloc彼らがあなたに手渡すこと。

そのため、権限のないメモリにアクセスしているため、ほとんどの OS で「セグメンテーション違反」と呼ばれる障害が発生し、プログラム突然終了します。


それについて何ができますか?

を呼び出してヒープに大きなブロックを割り当て、その範囲内の数字のみを入力char *p = malloc(1000000);して開始アドレスと終了アドレスを見つけます。printf("start:\t%p\nend\t%p\n",(void*)p,(void*)(p+1000000));

%p指定子 print 指定子は 16 進数で出力されるため、おそらく同じ基数でアドレスを入力する必要があることに注意してください。その点で標準ライブラリ関数strtolは役に立ちます。

より洗練されたアプローチは、OS の API を使用して任意のアドレスへのアクセス許可を要求することですが、値によっては OS が単純に拒否する可能性があります。

于 2012-10-11T20:28:58.787 に答える
2

あなたのために非常に単純化させてください...

ほとんどすべての最新のコンピューターでは、ほとんどのオペレーティング システムで、マシン内のメモリのほとんどがプログラムによって直接アドレス指定できません。ポインターを何かに向けて、それを読み取ろうとすることはできません。ほとんどの場合、失敗します。

一般的に、うまくいかないことが 3 つあります。

  • あなたが指している場所に記憶は存在しません。ポインターは広範囲の値を保持できますが、すべてが意味を持つわけではありません。郵便番号の番地のようなものです。技術的には、封筒には何でも入れることができます。一部のみ有効です。
  • 記憶は存在しますが、あなたのものではありません。コンピュータのメモリの大部分はオペレーティング システムによって「所有」されており、それに触れるとプログラムが終了します。これは安全のためです。
  • アドレスしようとしているメモリは、正しい範囲で有効ですが、正しいタイプではありません。前の例から、妥当な家屋番号があるかもしれませんが、その場所には家がありません。または、住所が実際にはアパートであり、数字だけでは不十分です。

1980 年代の古い 8 ビット コンピューターで 64k のメモリがフルに搭載されていれば、必要な場所を読み取るだけで問題ありませんでした。もうそれほどではありません。

于 2012-10-11T20:39:33.793 に答える
2

ここで、ポインターが欲しいだけで混乱が見られます。

まず、ユーザーに値を尋ねます。これで問題ありません。次に、その値をポインターの位置として割り当てますb。これは問題ないかもしれませんが、おそらくそうではありません。

*(-500) とはどういう意味ですか? *(0) はどういう意味ですか?

一般に、ユーザー入力を取得して、最初に確認したり操作したりせずに使用することはできません。これは、セキュリティ侵害が発生する場所の 1 つです。

逆参照メモリを試してみたい場合は、最初にいくつかの値をハードコーディングしてください。プログラムをデバッガーにロードして、何が起こるかを確認します。

int c;
b = 500;
c = *b; // what happens?
b = 0;
c = *b; // what happens?
b = -100;
c = *b; // what happens?
于 2012-10-11T20:24:59.553 に答える
1

理論的には、仮想アドレス空間 (32 ビット マシンでは 0 から 0xFFFFFFFF など) 内の任意のアドレスから読み取る権限があります。0 と負の数は問題ではありません。それらをポインターに割り当てると、負でない値にキャストされます。

実際には、うまくいきません。OS はそれ自体 (およびあなた) をこれから保護します。実際にはあなたのものではないアドレスから読み取ることはできません。つまり、メモリ ページを割り当てておらず、そこに何かを書き込んでいない場合、OS はそこから読み取ることを許可しません。

さらに、アドレス空間全体を実際に所有しているわけではありません-その下部はカーネルなどによって所有されているため、OSはアクセスできません。

于 2012-10-11T20:38:43.513 に答える
0

ご覧のとおり、b をポインターとして宣言しているため、a=b を実行するのは間違っています。セグメンテーション違反が発生します。ポインターは、整数、浮動小数点、または文字の値ではなく、ポインターのみを示します。別の方法として、b = &a を実行することもできます。これは、b が a のメモリ アドレスに表示されることを意味します。したがって、aに格納されている値を出力できます。

于 2012-10-14T12:53:59.590 に答える
0

私が聞いた限りでは、ポインターはもっぱらポジティブです。0 (NULL ポインター) は、何も指していないことが保証されており、プログラムが停止します。さらに、オペレーティング システム (私の記憶が正しければハードウェアも) はメモリ保護を提供します。これが、以前はプログラムが互いにクラッシュする可能性があった理由ですが、現在ではあまり一般的ではありません。プログラムを実行すると、OS はアクセスできるメモリを決定し、自分のものではないメモリにアクセスしようとすると segfault をスローします。

繰り返しますが、おそらくあなたはただ欲しかったのb = &aですか?これは、存在するb場所と同じ場所を指すため、に格納されている値と同じになります。a*ba

于 2012-10-11T20:30:15.497 に答える