0
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *p;
p = (char *)malloc(4*sizeof(char));
strcpy(p, "abcdabcd");
printf("%s\n", p);
free(p);
printf("%s\n", p);
return 0;
}

上記のコードを Ubuntu で実行してみました。ここでは、malloc から 4 バイトのメモリを割り当てています。次に、malloc によって割り当てられたメモリに 8 バイトをコピーしようとしました。警告やエラーは発生しませんでした。メモリのブロックを解放しようとし、解放されていたのと同じメモリを使用しようとしましたが、まったく問題はありませんでした。正しい文字列を出力しました。誰かがこの動作を説明できますか?

4

7 に答える 7

3

この動作は意味のある説明ができません。あなたのプログラムは未定義の動作を示します。つまり、何でも起こり得るということです。その「何でも」には、実験で観察した動作、つまり「正しい文字列を出力する」も含まれます。

今日は「正しい文字列を印刷」しました。明日は単にクラッシュするかもしれません。明後日、ハードドライブをフォーマットするかもしれません。これは、未定義の動作の概念の下では完全に許容されます。

于 2012-04-17T19:13:12.637 に答える
2

明らかに正しい操作は [未定義の動作] のクラスです。

于 2012-04-17T19:13:22.830 に答える
2

プログラムが起動されると、OS を介して仮想メモリへのアクセスが与えられます。通常、仮想ページにはいくつかの最小サイズ (たとえば 4 kb) があり、それが処理される最小サイズです。

したがって、このページ サイズ未満の malloc でメモリを要求すると、ブロック全体が利用可能になります。このブロックの一部/なし/すべてが他のプログラムによって使用される可能性があります。しかし、技術的にはまだ残っています:

1 byte | 1 byte | 1 byte | 1 byte | more memory you don't have....
 ^ char p points here

次に、 p からメモリに文字列をコピーするダンプを開始します。したがって、次のようになります。

a | b | c | d | the rest of the chars start dumping into somebody elses space!

このオーバーラップは定義されていません。つまり、未使用のメモリがある可能性があるため、今日はすべてが機能します。明日、その物理メモリ空間は OS によって保持され、上書きに失敗します。翌日、他のプログラムを中断します。その翌日、セグフォルト。

他の人が指摘したように、C はあなたに気を配っていません。

于 2012-04-17T19:24:49.820 に答える
1

C 言語は、メモリ チェックを保証しません。基本的に、自分のものではないメモリに書き込む場合 (たとえば、配列の境界を超えるメモリに書き込む)、または自分のものではないメモリから読み取る場合 (たとえば、メモリを解放してあきらめたメモリから読み取る場合) ) 何が起こるかわからない。

ただし、オペレーティング システムによって、これらのいずれかの実行が妨げられる場合と妨げられない場合があります。通常、これが発生すると、「Bus Error」または「Segmentation Fault」が発生します。ただし、これらのいずれかが発生することも保証されていません。

最善の方法は、防御的にコーディングすることです。配列の長さを追跡し、配列にコピーするときに配列サイズを超えていないことをアサートまたはチェックします。

他にできることは、デバッグです。Valgrindは、あなたが説明したような問題をキャッチするための非常に効果的なツールです。これは、malloc していないメモリの読み取りまたは書き込みの両方の状況を示している可能性があります。また、メモリを malloc した後で解放するのを忘れた場合など、リークを特定することもできます。

于 2012-04-17T19:17:49.720 に答える
0

他のすべての人が言ったように、あなたのコードは未定義の動作を引き起こします(何でも起こり得ます)。

ヒープ メモリ アロケータ (malloc) は、領域を解放した後に領域に格納されたデータに対して責任を負いません

malloc の役割を理解すると、結果が表示される理由、間違ったプログラミング方法、および常に機能しない理由を説明するのに役立ちます。

Malloc は glibc のヒープ メモリ アロケータ (_int_malloc および _int_free) です。ここでそのコードを表示できます [ http://code.woboq.org/userspace/glibc/malloc/malloc.c.html#_int_malloc]

誰かがこの動作を説明できますか?

コミカルな例は、質問をすばやく明確にするのに役立ちます。

どの部屋 ( memory )にも鍵がないモーテル ( sbrk(2) ) から部屋 ( memory )を借りているとします。. 受付係 ( malloc ) に行き、部屋 (メモリー) を要求すると、彼女は利用可能な部屋を提供し、部屋 (メモリー) を受け取り、それを使用します。 あなたはそれを使い果たし、今度はそれを再び使用しないことを彼女に約束します(解放します). 彼女は自分の本に、あなたの部屋 (メモリー) は無料で、他の人に割り当てることができると書いています。部屋を他の誰かに譲るかどうかは完全に彼女の願いです。


あなたはしばらくしてからあなたの部屋を見に来ます(受付係はあなたをチェックしません)、あなたが部屋を使用している人がいない場合は幸運です(あなたが残したのと同じくらい散らかっています!)

受付係 (malloc) の仕事は、退去後 (無料) に約束を守ることを信頼して、部屋 (メモリ) をできるだけ早くあなたに割り当てることです。彼女の仕事は、部屋の使用を妨げることではありません (メモリー) !

許可されていない場所(読み取り専用領域)にアクセスすると、所有者(カーネル)は激怒します(例外)。

私は初心者で、このように答えるのが適切かどうかわかりません。間違っている場合は教えてください。mallocを使用することを強くお勧めします

于 2014-09-10T09:58:48.477 に答える
0

未定義の動作を呼び出したと言った人は誰でも正しいです。

正しく動作しているように見える理由は、プラットフォームでのヒープ マネージャーの特定の実装の副作用である可能性があります。たとえば、多くのメモリ マネージャーは割り当てを都合のよいサイズに丸め、最小サイズは多くの場合 8 バイトまたは 16 バイトです。このような実装の詳細に依存するべきではありません。

一部のプラットフォームには、プログラムの開発中にこれらの種類の仮定を把握しようとするツールがあります。

于 2012-04-17T19:33:16.970 に答える
0

ブロックの配置に沿って割り当てられると思います。これが、この場合、魔法のような追加のメモリを提供した理由です。より大きなバイト倍数に上げてみてください(たとえば、16、64など。より正確である必要があり、それを超えるとセグメンテーション違反になる可能性があります)。ただし、malloc されたチャンクの後のメモリもプログラムのメモリ空間の一部である場合は、segfault も発生しないことに注意してください。

一般に、メモリのプログラム セグメントにとどまっている限り、必要なすべてを喜んで読み書きできます (もちろん、自己責任で:D)。

本当にプログラムをチェックしたい場合は、「valgrind」を使用して実行してください

于 2012-04-17T19:19:42.660 に答える