24

次のコードを使用します。

int *p = malloc(2 * sizeof *p);

p[0] = 10;  //Using the two spaces I
p[1] = 20;  //allocated with malloc before.

p[2] = 30;  //Using another space that I didn't allocate for. 

printf("%d", *(p+1)); //Correctly prints 20
printf("%d", *(p+2)); //Also, correctly prints 30
                      //although I didn't allocate space for it

この行malloc(2 * sizeof *p)で、2 つの整数にスペースを割り当てていますよね?しかし、3 番目の位置に を追加しintても、正しく割り当てられ、取得可能になります。

私の質問は、なぜ使用時にサイズを指定するのmallocですか?

4

17 に答える 17

134

単純な論理: 合法的な駐車スペースに駐車しなければ、何も起こらないかもしれませんが、時折、車がレッカー移動され、高額の罰金を科せられる可能性があります。また、車が牽引されたポンドに向かう途中で、トラックに轢かれることもあります。

mallocは、あなたが求めた数の合法的な駐車スペースを提供します。他の場所に駐車することもできます。うまくいくように見えるかもしれませんが、うまくいかないこともあります。

このような質問については、C FAQ のメモリ割り当てのセクションを参考にしてください。7.3bを参照してください。

関連する (ユーモラスな) ノートについては、ARTによるNG集のリストも参照してください。

于 2009-08-06T20:00:14.997 に答える
32

Cさん、頭を撃たせてください。ヒープでランダム メモリを使用しました。予期せぬ結果を伴います。

免責事項: 私の最後の本物の C プログラミングは、約 15 年前に行われました。

于 2009-08-06T19:51:40.120 に答える
29

なぜこれが「機能する」のか、例えを挙げてみましょう。

絵を描く必要があると仮定して、一枚の紙を取り出し、テーブルの上に平らに置き、絵を描き始めます。

残念ながら、紙は十分な大きさではありませんが、気にせず、気付かずに、絵を描き続けます。

完了したら、一歩下がって自分の絵を見てください。意図したとおりに、正確に描いたとおりに、見栄えがします。

誰かがやってきて、あなたがたどり着く前にテーブルに置き忘れた紙切れを拾うまでは。

現在、図面の一部が欠落しています。あの人の紙にあなたが描いた作品。

さらに、その人はあなたの絵の一部を自分の紙に載せています。

したがって、メモリ使用量が機能しているように見える場合でも、プログラムが終了したためにのみ機能します。実行中のプログラムにそのようなバグをしばらく残しておくと、おかしな結果やクラッシュなどが発生することを保証できます。

C はステロイドを使ったチェーンソーのように作られています。できないことはほとんどありません。これは、自分が何をしているのかを知る必要があることも意味します。

于 2009-08-06T20:06:11.867 に答える
13

あなたは(不)運が良かった。p[3] へのアクセスは未定義です。そのメモリを自分で割り当てていないためです。配列の末尾の読み取り/書き込みは、C プログラムが不思議な方法でクラッシュする可能性がある方法の 1 つです。

たとえば、これにより、malloc によって割り当てられた他の変数の値が変更される可能性があります。つまり、後でクラッシュする可能性があり、データを上書きした (関係のない) コードを見つけるのが非常に難しくなります。

さらに悪いことに、他のデータを上書きして気付かないこともあります。これが誤って誰かに借りている金額を上書きしてしまうと想像してみてください;-)

于 2009-08-06T19:52:57.653 に答える
4

これを試して:

int main ( int argc, char *argv[] ) {
  int *p = malloc(2 * sizeof *p);
  int *q = malloc(sizeof *q);
  *q = 100;

  p[0] = 10;    p[1] = 20;    p[2] = 30;    p[3] = 40;
  p[4] = 50;    p[5] = 60;    p[6] = 70;


  printf("%d\n", *q);

  return 0;
}

私のマシンでは、次のように出力されます。

50

これは、p に割り当てられたメモリを上書きし、q を踏みつけたためです。

アラインメントの制限により、malloc は p と q を連続したメモリに配置できないことに注意してください。

于 2009-08-06T20:21:15.783 に答える
4

実際、mallocは 3 番目の整数に十分なスペースを割り当てていませんが、「幸運」で、プログラムはクラッシュしませんでした。malloc が要求したとおりに割り当てられていることを確認するだけで、それ以上は必要ありません。つまり、プログラムは、割り当てられていないメモリの一部に書き込みました。

そのため、malloc は必要なメモリのサイズを知る必要があります。これは、メモリで何をするか、メモリに書き込む予定のオブジェクトの数などがわからないためです...

于 2009-08-06T19:51:51.010 に答える
4

これはすべてCに戻り、足を撃ちます。これができるからといって、そうすべきだというわけではありません。p+3 の値は、malloc を使用して特に割り当てない限り、そこに設定した値であるとは限りません。

于 2009-08-06T19:52:07.907 に答える
2

プラットフォームによっては、p[500] もおそらく「機能」します。

于 2009-08-06T20:09:38.160 に答える
2

メモリは、数値を格納できる列挙可能なスロットの連続した行として表されます。malloc 関数は、これらのスロットの一部を独自の追跡情報に使用するだけでなく、必要なサイズよりも大きなスロットを返す場合があるため、後でそれらを返す場合があります。使用できないほど小さなメモリのチャンクで立ち往生することはありません。3 番目の int は、malloc 自身のデータ、返されたチャンクに残っている空き領域、または malloc が OS から要求したが、まだ分割されていない保留中のメモリの領域に着陸します。

于 2009-08-06T20:01:01.547 に答える
1

2 つの整数のスペースを求めています。p[3] は、4 つの整数のためのスペースがあると想定しています!

===================

必要なメモリの量を推測できないため、必要な量を malloc に伝える必要があります。

malloc は、少なくとも必要な量のメモリを返す限り、何でも実行できます。

レストランで席を頼むようなものです。必要以上に大きなテーブルが与えられる場合があります。または、他の人と一緒にテーブルに着席することもできます。または、1 席のテー​​ブルが与えられる場合もあります。Malloc は、あなたが 1 席を確保する限り、何でも自由に行うことができます。

malloc を使用するための「契約」の一部として、要求した量を取得することが保証されているため、要求した量を超えてメモリを参照してはいけません。

于 2009-08-06T20:08:18.443 に答える
1

を使用する場合malloc()、ランタイム ライブラリとの契約に同意することになります。この契約では、使用する予定のメモリを要求することに同意し、それを提供することに同意します。友達同士で口頭だけで握手するような合意は、人々をしばしばトラブルに巻き込みます。割り当て範囲外のアドレスにアクセスすると、約束違反になります。

その時点で、標準が「未定義の動作」と呼ぶものを要求し、コンパイラとライブラリはそれに応じて何でもすることができます。「正しく」動作しているように見えることさえ許されます。

この間違いをキャッチするテスト ケースを作成するのが難しい場合があるため、正しく動作することが非常に多いのは非常に残念です。malloc()それをテストするための最良のアプローチには、ブロックサイズの制限を追跡し、あらゆる機会にヒープの健全性を積極的にテストする実装に置き換えるか、valgrindのようなツールを使用して「外部」からプログラムの動作を監視することが含まれます。バッファメモリの誤用を発見します。理想的には、そのような誤用は早期に失敗し、大声で失敗します。

元の割り当てに近い要素を使用すると成功することが多い理由の 1 つは、アロケーターがアライメント保証の都合のよい倍数に関連するブロックを提供することが多く、その結果、1 つの割り当ての終わりに開始前の「予備の」バイトが生じることが多いためです。次の。ただし、アロケーターは多くの場合、それらのバイトの近くにヒープ自体を管理するために必要な重要な情報を格納するため、割り当てを超えるとmalloc()、2 番目の割り当てを正常に行うために必要なデータが破壊される可能性があります。

編集: OPは*(p+2)交絡の副次的な問題を修正したp[1]ので、回答を編集してその点を削除しました。

于 2009-08-06T20:10:10.313 に答える
0

malloc は、動的に割り当てられるプログラムによって使用されるメモリの一部であるヒープにスペースを割り当てているためです。次に、基盤となるOSは、プログラムに要求された量の仮想メモリを提供します(または、mallocの戻り値を常にチェックしてエラー状態を確認する必要があることを意味するエラーが発生した場合はそうではありません)。 OS を作成していない限り、ページングなどの複雑なことを含む巧妙な魔法。

于 2009-08-06T20:02:00.797 に答える
0

誰もが言ったように、実際には割り当てられていないメモリに書き込んでいます。つまり、データを上書きする何かが発生する可能性があります。問題を示すために、次のようなことを試すことができます。

int *p = malloc(2 * sizeof(int));
p[0] = 10; p[1] = 20; p[2] = 30;
int *q = malloc(2 * sizeof(int));
q[0] = 0; // This may or may not get written to p[2], overwriting your 30.

printf("%d", p[0]); // Correctly prints 10
printf("%d", p[1]); // Correctly prints 20
printf("%d", p[2]); // May print 30, or 0, or possibly something else entirely.

プログラムが p[2] で q にスペースを割り当てることを保証する方法はありません。実際には、まったく異なる場所を選択する場合があります。しかし、このような単純なプログラムの場合、可能性が高く、p [2] が配置される場所に q を割り当てると、範囲外エラーが明確に示されます。

于 2009-08-06T20:02:03.433 に答える
0

malloc() に指定されたサイズの理由は、システム上の各プロセスに割り当てられたスペースの量をメモリ マネージャーが追跡するためです。これらのテーブルは、誰がどのくらいのスペースを割り当てたか、および free() 可能なアドレスをシステムが知るのに役立ちます。

次に、c を使用すると、RAM の任意の部分にいつでも書き込むことができます。カーネルによって特定のセクションへの書き込みが妨げられ、保護違反が発生する場合がありますが、プログラマーの書き込みを妨げるものは何もありません。

3 番目に、おそらく最初に malloc() を実行しても、単純に 8 バイトがプロセスに割り当てられるわけではありません。これは実装に依存しますが、ページ サイズのチャンクを割り当てる方が簡単であるという理由だけで、メモリ マネージャーがページ全体を割り当てる可能性が高くなります。その後の malloc() は、以前の malloc( )ed ページ。

于 2009-08-06T20:12:25.427 に答える
0

* (p+3) を使用すると、2*sizeof(* p) を使用しても範囲外にアドレス指定しているため、無効なメモリ ブロックにアクセスしているため、セグ フォールトに最適です。

それ以外の場合、サイズ b/c を指定すると、関数は、そのポインター用にプログラムに割り当てるヒープ メモリからのブロックの大きさを認識しません。

于 2009-08-06T19:51:12.603 に答える
0

malloc() は BYTES 単位で割り当てるためです。したがって、(たとえば) 2 つの整数を割り当てたい場合は、2 つの整数のサイズをバイト単位で指定する必要があります。整数のサイズは sizeof(int) を使用して見つけることができるため、2 つの整数のバイト単位のサイズは 2 * sizeof(int) です。これをすべてまとめると、次のようになります。

int * p = malloc(2 * sizeof(int));

注:上記は2つの整数にのみスペースを割り当てるため、3番目を割り当てるのは非常にいたずらです。クラッシュしないのは幸運です。:)

于 2009-08-06T19:55:12.690 に答える
-3

行う :

int *p = malloc(2 * sizeof(*p)); // wrong (if type is something greater than a machine word)

[type] *p = malloc(2 * sizeof([type])); // right.
于 2009-08-06T21:37:31.040 に答える