1

私は次のコードを取得しました:

char buffer[2047];
int charsRead;

do {
    if(fscanf(file, "%2047[^\n]%n%*c", buffer, &charsRead) == 1) {
        // Do something
    }
} while (charsRead == 2047);

このコードを動的に割り当てられた変数を使用するように変換して、このコードを頻繁に呼び出すときに大量のメモリリークが発生しないようにしたかったのです。したがって、私はこれを試しました:

char *buffer = malloc(sizeof(char) * 2047);
int *charsRead = malloc(sizeof(int));

do {
    if(fscanf(file, "%2047[^\n]%n%*c", *buffer, charsRead) == 1) {
        // Do something
    }
} while (*charsRead == 2047);

残念ながら、これは機能しません。fscanf呼び出しでのifステートメントの直前に、常に「EXC_BAD_ACCESS」エラーが発生します。私は何が間違っているのですか?

助けてくれてありがとう!

--Ry

4

5 に答える 5

5

コンパイラがメモリを管理しているため、元のコードは新しいコードよりもリークする可能性がはるかに低くなりますが、必要に応じて次のように変更してください。

if(fscanf(file, "%2047[^\n]%n%*c", buffer, charsRead) == 1) {

コードの最初のビットで行った以上に、ここで buffer を逆参照したくありません。そうすることでバッファ内の最初の文字が得られますが、バッファのアドレスが必要です。

于 2010-03-27T14:35:46.260 に答える
1

コードに3つの問題があります。まず、あなたが提起した質問に答えるには、の3番目の引数としてbufferではなく渡す必要があります。ニールの答えは、その理由をうまく説明しています。*bufferfscanf

次に、バッファオーバーフローが発生します。fscanfスキャンされた入力にヌル終了文字を自動的に追加します。与えるバッファーには、スキャンされた入力ヌル終了文字のfscanfための十分なスペースが必要です。2,047文字をスキャンする場合は、バッファーの長さを2,048文字にする必要があります。

第三に、コードの新しいバージョンはメモリリークのあるバージョンです。以前のバージョンでは、バッファがスタック(またはグローバル変数の場合は静的ストレージ)に割り当てられていたため、リークは発生しませんでした。関数が戻ると、バッファによって使用されるスタックスペースが再利用されます。を使用してヒープからバッファを割り当てるということは、バッファの使用が終了したときに後で呼び出すことによって、割り当てられたヒープメモリを再利用する責任があることをmalloc意味します。free私の意見ではbuffer、スタックに割り当てた元のバージョンのコードの方がはるかに優れていました。

新しいバージョンが望ましい唯一のケースは、スタックスペースが非常に限られているシステムをターゲットにしている場合です(一部の組み込みシステムの場合のように)。このようなシステムでは、スタックに大きなバッファを割り当てることはお勧めできません。このような場合、mallocスタックオーバーフローの可能性を回避するために、を使用してヒープからバッファを割り当てることが望ましい場合があります。その場合は、を呼び出してメモリの割り当てを解除することにより、メモリリークを回避するように注意する必要がありfreeます。

于 2010-03-27T15:16:18.363 に答える
1

終端の NUL も保持できるように、読み取る文字数より少なくとも 1 バイト長くバッファを作成することをお勧めします。それを除けば、オリジナルは漏れません。コードを含む関数が戻ると、それらの変数はなくなります。それにリークがある場合、それはあなたが私たちに見せていない何かにあるに違いありません.

于 2010-03-27T14:39:07.703 に答える
1

「何が間違っているのか」に答えるために、bufferポインタを逆参照しています。として宣言されているのでchar *、書く*bufferとバッファの最初の文字を取得しているので、すべてが必要なので*、次のように先頭から を削除するだけです。

if(fscanf(file, "%2047[^\n]%n%*c", buffer, charsRead) == 1) {

しかし、あなたは間違った前提を持っているようです。最初のコード スニペットのように、(スタック上で) 静的に割り当てられた配列を使用しても、"メモリ リーク" は発生しません。まったく逆です。2 番目のコード スニペットには解放がないため、これがメモリ リークの原因となるコードです。コンパイル時に配列に必要なサイズ (この場合は 2047) がわかっている場合は、動的に割り当てる代わりに静的配列を使用する必要があります (通常は常に例外がありますが、まだそれほど進んでいません)。 1。

于 2010-03-27T14:39:28.233 に答える
0

charsRead を動的に割り当てても、何も達成されません。以前に charsRead を使用した方法に戻ると、おそらく問題が解決するでしょう。

于 2010-03-27T14:39:09.623 に答える