0
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int x;
    int *in, *begin;
    in = (int *)malloc(sizeof(int));
    begin = in;
    while ((x = getchar()) != EOF) {
        *in = x;
        in++;
        in = (int *)malloc(sizeof(int));
    }
    *in = EOF;
    while ((x = *begin) != EOF) {
        putchar(x);
        begin++;
    }
    free(in);
    return 0;
}

私はそれがそうであることをこっそりと疑っています。

char string[255]; fgets(string, sizeof(string));このプログラムでは、などを使用するのではなく、ポインターを使用して不定サイズのユーザー入力をメモリに格納しようとしています。

編集:プログラムを実行してもクラッシュなどはありません。解放されていないメモリが割り当てられているように感じます。

4

5 に答える 5

2

はい、プログラムにメモリ リークがあります。

int *in, *begin;
in = (int *)malloc(sizeof(int));  /* allocate space for 1 int, at location "X" */
begin = in;
while ((x = getchar()) != EOF) {
    *in = x; 
    in++;    /* "in" increments address (to location) "X+1" */
    in = (int *)malloc(sizeof(int)); /* address "X+1" is lost as malloc returns  
                                        a different memory location, *not*
                                        necessarily at "X+2". Access to 
                                        previous data other than pointed to by 
                                        "begin" is lost */
}

*in = '\0';  /* this makes probably more senese than assigining EOF here */

free()メモリを割り当てるときに、対応する呼び出しが必要です。

また、入力が正しく保存されているとは思いません。

inデータを格納するためのメモリの連続ブロックが与えられることはありません。代わりに、 an を格納するサイズの単一のメモリ ロケーションが繰り返し割り当てられ、 に割り当てられますが、このメモリがどこにあるかは実際にはわからないため、単一のポインタだけがそれらを追跡しているため、これらの割り当てはすべて失われます。intinin

つまり、リークは、 のサイズのメモリを繰り返し割り当て、intに割り当てin、次にループによってその場所への参照を失うことで構成されます。

変数beginは最初に入力された最初の項目を指しますが、出力ループでポインター値が 1 ずつインクリメントされるため、その後不明なメモリをトラップします。

より良いアプローチは、開始時に単一のより大きな連続バッファーを割り当ててから、inポインターをインクリメントするときにそれを使用するか、より少ない量で開始し、realloc()必要に応じてメモリ使用量などを監視することです (ただし、節約するためのオーバーヘッドははるかに大きくなります)。数バイトのメモリ)。

EOFまた、に割り当てるのではなく、最初のループの最後にin、null 文字を入れる方が理にかなっています。

最後に、free(in)プログラムの最後の呼び出しは、1 つのメモリ ロケーションのみを解放し、以前に割り当てられた他のメモリは解放しません。

これは機能する簡単にまとめられたバージョンです。元のコードに最小限の変更を加え、コード構造をそのまま維持しようとしました(そもそも2つのループでこのように書く理由があったと思います) 1 つのループだけで、はるかにコンパクトに記述できます。

最初に100文字のスペースを割り当て、必要に応じてこれを調整するか、最初は割り当てを少なくしてから、必要に応じてメモリ消費量とrealloc()メモリを増やします(これは最初の意図だったと思いますが、正しく実装されていません)。

int main(void) {
    int x;
    int *in, *begin;
    int *start_loc;
    in = (int *)malloc(sizeof(int) * 100); /* continious space */
    begin = in;
    start_loc = in; /* keep track of start location for final free() call */

    while ((x = getchar()) != EOF) {
        *in = x;
        in++;
    }
    *in = 0;  /* terminator for the input string/data */

    while (*begin != 0) {   /* simplified */
        putchar(*begin);
        begin++;
    }

    free(start_loc);  /* free allocated memory */
    return 0;
}

これは、新しい変数を使用せずにstart_loc(たとえば、再利用inして) 記述できますが、メモリ割り当ての開始を追跡することの重要性と、割り当てられたメモリを正しく解放する機能を強調するために、この方法で記述することを選択しました。メモリ リークの問題に対処します。

于 2012-06-17T00:34:45.097 に答える
1

リーヴォンの答えは正しいです。ここの値を増やしinます:

in++;

...しかし、ここで任意のアドレスに再割り当てします。

in = (int *)malloc(sizeof(int));

あなたがやろうとしていることを達成するには、次のいずれかを行う必要があります。

  • 連続したメモリの大きなチャンクを一度に割り当て、拡張する必要があるときはいつでもrealloc()を割り当てます(これはあなたが達成しようとしていることです)、または;
  • リンクリストを使用して、連続していないメモリアドレスのリストをナビゲートします(これは実際に何とか書き込んだものです)。
于 2012-06-17T00:38:11.333 に答える
1

はいあなたが持っています。Free1つの整数のメモリの割り当てを解除します。あなたはあなたがしfreeたすべての呼び出しのためにmalloc呼び出す必要があります。

また、文字を連続バッファに格納するmallocには、最初に一定量のメモリを使用し、realloc読み取った文字が最初に割り当てられたメモリよりも多くなる場合に使用する必要があります。

\0また、文字列の最後にもう1文字を割り当てることを忘れないでください。

終わったら、電話free(buffer)して...成功!メモリリークはありません!

そしてそのためのコード:

/* Start with an initial size */
int size = 128;
char *buffer = (char *)malloc(size + 1);
int i = 0;
while ((x = getchar()) != EOF) {
        buffer[i] = x;
        i++;
        if(i == size){
           /*Do realloc and increase size */
        }
}
buffer[i] = '\0';
/* Do what you want with buffer */
free(buffer);
于 2012-06-17T00:43:30.770 に答える
1

もちろん、そこへのすべての呼び出しは、プログラム内mallocの対応する呼び出しである必要があるため、メモリリークがありfreeます。

あなたのプログラムmallocでは が数回呼び出されていますが、 への呼び出しは 1 回だけfreeです。

于 2012-06-17T00:33:43.557 に答える
0

mallocを使用してメモリを割り当てるときは、メモリを指すポインタがNULLでないことを確認する必要があります。メモリを解放した後は、ポインタをNULLに設定することをお勧めします。

于 2012-06-17T06:33:28.187 に答える