8

なので、今回はタイトルの付け方がよくわかりません。まず最初に、このページで、質問が「宿題」に関するものである場合の警告について、いくつかのコメントを見たことをお伝えしたいと思います。私はそうですが、それも完成していて、コードで何が起こっているのかをさらに理解したいだけです。

しばらくの間、投稿や本も読んでいますが、まだ足りないものがあると思います。

使用したコードでよく理解できないコードが 2 行あります。作業は、引数として使用されるファイルを取得することです (ファイルが 0 の場合は、stdin から読み取ります)、標準出力に逆方向に出力します。このすべて、タグに入れようとしたときに C について話します。

最初の問題はこれです:

array = realloc (array, 0);

配列が次のように定義されている場所

char **array;

そして問題は、 free が機能せず、使用されているスペースを解放しないことです (間違って使用したのでしょうか? 他の場所では使用方法を知っていましたが、今回はそうではありません)。私が行ったテストと読んだことから、realloc も同じことをしていると思いますが、100% ではありません。

2 つ目は次のとおりです。

char* alloc = malloc (strlen ((char*)string)+1);

alloc を使用して、配列に入れる行の正確な長さをコピーするので、その後、テキストを逆方向に出力できます。

問題は、なぜその +1 を使わなければならないのかということです。なんらかの理由で使用しないと機能しないということです。別の番号で試してみると、毎回機能しますが、+1を行わないと正しく機能しません。

おそらく質問が曖昧すぎて、実際に答えられるには下手な書き方であることはわかっていますが、それについてはよくわかりません.

4

6 に答える 6

8

reallocサイズが 0の場合の動作は、C11 (現在のバージョン) では異なります。標準では (C11 の場合は 7.20.3.1、C1x の場合は 7.22.3.1) と記載されています。

要求されたスペースのサイズがゼロの場合、動作は実装定義です。null ポインターが返されるか、サイズがゼロ以外の値であるかのように動作します。ただし、返されたポインターはオブジェクトへのアクセスには使用されません。

したがって、使用freeし、依存しないでくださいrealloc

経由で文字列を処理するときchar*は、ヌル ターミネータに余分な文字を 1 つ含めることを常に忘れないで\0ください。これは、文字列の終了位置を示す通常の方法です (もう 1 つは明示的な文字列の長さです)。

使用するときは、正確mallocfree一致させる必要があることに注意してください。またはfreeによって返される正確なポインター (値) が必要です。mallocrealloc

于 2013-05-26T14:13:05.743 に答える
3

配列 = realloc (配列、0);

サイズが 0 の Realloc は、一部の C 実装ではfree() と同等ですが、すべてではありません。

そして問題は、 free が機能しないことです。使用されているスペースを解放しません

char **arrayアプリケーションでそれがどのような意味で、どのように割り当てられているかを考えてください。多くの場合、ポインターツーポインターは、配列の配列として表現される 2 次元配列として使用されます。ほとんどのアプリケーションは、 malloc() への複数回の呼び出しでこれらを割り当てます。arrayは単に の配列でありchar *、その配列の各要素は の配列ですchar。の配列で free() を呼び出すだけで、 の配列が解放されますが、 の配列のそれぞれchar *が解放されるchar *わけではありませんchar

here で説明されているように、 free() を複数回呼び出す必要があります。

私は別の数字で試してみましたが、毎回動作しますが、+1 をしないと正しく動作しません。

C 文字列はヌルで終了します。つまり、プログラムは、文字列の末尾にヌル文字を配置して、文字列の終了位置を追跡します。つまり、長さ N の C 文字列には、N 文字分のスペースと 1 つのヌル文字が必要です。この場合、メモリ空間の全体の長さは N+1 になります。

于 2013-05-26T13:59:47.353 に答える
2

最初の質問:

realloc(array, 0)と同等ではありませんfree(array)

標準 (C99、§7.20.3.4 ¶1) は次のように述べています。

このrealloc関数は、 が指す古いオブジェクトの割り当てを解除し、ptrで指定されたサイズの新しいオブジェクトへのポインターを返しますsize

size==0;の「特別なケース」はありません。したがって、サイズがゼロのオブジェクトへのポインターを取得していますが、これはまだオブジェクトである可能性があり、解放する必要があります。

realloc興味深いことに、はそのような状況では単純に失敗して を返す可能性があると思いますNULL。この場合、コード内でメモリがリークされます。realloc失敗すると、渡した元のメモリ ブロックが解放されないためです (これが決して解放しない理由ですarray = realloc(array, size)が、常に中間変数を使用しNULLて順番にチェックします)。メモリリークを避けるため)。

実際、標準では、私が覚えているsize==0だけでなく、すべてのメモリ割り当て関数に対して実装定義の動作を指定しています。mallocしたがって、以下に説明するように、動作は実装定義です。

より直感的には、他のポインターの+ +reallocと「概念的に同等」であり、メモリの 0 バイトのチャンクを -ing すると、何も格納するために使用されない一意のポインターが返されます (0 バイトを要求しました)。まだ編集されていません。したがって、いいえ、そのように使用しないでください。一部の実装 (つまり、Linux) で動作する可能性がありますが、保証されていません。mallocmemcpyfreemallocNULLfreerealloc

また、それが機能しないとどのように推測したかは明確でfreeはありません。あなたがこれを確信したかもしれない2つの方法を考えることができます:

  1. arrayおよびそれが指すデータの値は変更されません。
  2. タスクマネージャーで割り当てられたメモリ/ top/何でも減少しません。

最初のケースでは、それは正常です。ポインターを解放しても、魔法のように消去されることはありません。ポインターはポインターが指している場所を指し続けますが、そのメモリーはもはやあなたのものではありません。C ランタイムに戻っており、おそらく将来的には再び解放されるでしょう。malloc. そのため、そのことは「ダングリング ポインター」と呼ばれ、多くの人は、既に解放されているメモリのスペースに再び書き込むことを避けるために、freeそれを設定した後です。NULL

2 つ目については、アロケーターがすぐにオペレーティング システムにメモリを返さないというのが一般的なポリシーです (非常に大きなチャンクについて話している場合を除きます)。おそらく、アプリケーションはすぐにそのようなメモリを必要とし、現在のプロセスのためにそのメモリを保持することで、OS からメモリを取得/提供するための連続的なシステム コールを回避できるという考えです。通常使用されるメモリを監視するためのシステム ユーティリティは、OS がプロセスに与えたものしか見ることができないため、メモリ使用量の減少が見られないのは正常です。

ちなみに、 でchar ** array割り当てられたものへのポインタが含まれている場合mallocは、最初にfreeそれらにアクセスする必要があります。そうしないと、メモリリークが発生します。


2 番目の質問:

C 文字列は null で終了します。つまり、文字列の最後の文字は常に\0文字列の終わりを示すastrlenであり、null ターミネータを除いた文字列の長さを示します。そのため、追加しないと、実際に文字列を格納するために必要なメモリよりも+11 つ少なく割り当てられます。char


補遺

動作しないということは、クラッシュしたことを意味します(問題は別の場所にある可能性があります)が、使用済みの動的使用メモリを削除するという意味で、それを realloc(X, 0) に変更すると動作しました

マンページにあるように、

malloc()、calloc()、realloc()、または free() でのクラッシュは、ほとんどの場合、割り当てられたチャンクのオーバーフローや同じポインターの 2 回の解放など、ヒープの破損に関連しています。

コードに他のバグがある可能性がありますが、それを見なければ、どこで何が問題なのかを判断することはできません。

于 2013-05-26T14:13:30.637 に答える
1

2番目の質問について:

C では、文字列はヌル文字 '\0' で終了する必要があります。strlen を使用する場合、この文字はカウントされませんが、十分なスペースを割り当てる必要があります (これが +1 です)。

null 文字を含まない文字列を出力しようとすると、いくつかの「ランダムな」文字が出力される可能性がありますが、クラッシュする可能性もあります。strcpy を使用すると、バッファ オーバーフローが発生します。

于 2013-05-26T13:52:34.227 に答える
1

互換性を維持したい場合は、realloc(p,0)が と同等になることはfree(p)なく、後続の解放がないゼロ割り当ては、Linux でも単純明快なメモリ リークです。

/* leak.c */
#include <mcheck.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
    void* p;
    mtrace();
    p = malloc(0x100);
    p = realloc(p, 0);
    exit(EXIT_SUCCESS);
}

$ cc -g leak.c -o leak
$ export MALLOC_TRACE=/tmp/t
$ ./leak
$ mtrace ./leak $MALLOC_TRACE
于 2013-09-11T15:49:39.810 に答える