1

少し前にこのサイトで関数を見ました。

getc と stdin を使用して文字列を取得し、文字列を格納するために必要なだけのメモリを正確に割り当てる関数です。次に、上記の文字列で満たされた割り当てられたメモリへのポインタを返します。

私の質問は、この関数に (割り当てられたメモリを後で手動で解放する必要がある以外に) 欠点はありますか? それを改善するためにあなたは何をしますか?

char *getstr(void)
{
    char *str = NULL, *tmp = NULL;
    int ch = -1, sz = 0, pt = 0;

    while(ch)
    {
        ch = getc(stdin);
        if (ch == EOF || ch == 0x0A || ch == 0x0D) ch = 0;
        if (sz <= pt)
        {
            sz++; 
            tmp = realloc(str, sz * sizeof(char));
            if(!tmp) return NULL;
            str = tmp;
        }
        str[pt++] = ch;
    }

    return str;
}

ここであなたの提案を使用した後、更新されたコードです。この関数はユーザー入力に使用されているため、バッファーに 256 バイトを使用することにしました。

char *getstr(void)
{
    char *str, *tmp = NULL;
    int ch = -1, bff = 256, pt = 0;

    str = malloc(bff);
        if(!str) 
        {
            printf(\nError! Memory allocation failed!");
            return 0x00;
        }
    while(ch)
    {
        ch = getc(stdin);
        if (ch == EOF || ch == '\n' || ch == '\r') ch = 0;
        if (bff <= pt)
        {
            bff += 256; 
            tmp = realloc(str, bff);
            if(!tmp) 
            {
                free(str);
                printf("\nError! Memory allocation failed!");
                return 0x00;
            }
            str = tmp;
        }
        str[pt++] = ch;
    }
    tmp = realloc(str, pt);
    if(!tmp)
    {
        free(str);
        printf("\nError! Memory allocation failed!");
        return 0x00;
    }
    str = tmp;

    return str;
}
4

4 に答える 4

2
  1. '\n'=='0xa'と'\r'=='\0d'に依存します。理由はありません。\rとを意味する場合は\n、それらを使用してください。
  2. 読む文字ごとに再割り当てするのは、不当に遅くなる可能性があります。
  3. sizeof(char)1であることが保証されているので、意味がありません。
  4. メモリのブロックを割り当てた場合、reallocは失敗し、戻りまたは解放せずにNULLを返すstrため、メモリがリークします。
  5. #4のように、インターフェースは部分的な障害を示す方法を提供しません。あなたができることは、文字列を返すかどうかだけです。膨大な入力文字列がある場合、すべてではなく一部を読んだことを示す方法はありません。
于 2012-08-22T14:50:32.510 に答える
2

はい、主な問題はreallocかなり遅いことであり、各キャラクターに対して繰り返し呼び出すことは一般的に悪い考えです。

最初に一定量のメモリを割り当ててみてください。たとえば、N=100文字を入力し、さらに必要な場合は、、などのように取得2*N4*Nます。最大2倍のメモリしか消費しませんが、実行時間を大幅に節約できます。

于 2012-08-22T14:48:07.603 に答える
2

それは過度に倹約的なIMOであり、ほとんどの設定では無意味なメモリを無限に節約するためにパフォーマンスを犠牲にするという間違いを犯しています. realloc のような割り当て呼び出しはシステムにとって面倒な作業になる可能性があり、ここではすべてのバイトに対して行われます。

読み込むためのローカル バッファ (たとえば 4KB) を用意し、実際に読み込まれた長さに基づいて戻り文字列を割り当てる方がよいでしょう。すべてを使用するかどうかに関係なく、通常のシステムのスタック* はとにかく 4 ~ 8MB であることに注意してください。読み取った文字列が 4KB を超えることが判明した場合は、同様のループを作成して、戻り文字列に割り当ててコピーすることができます。同様の考え方ですが、ヒープ割り当てはすべてのバイトではなく 4096 バイトごとに発生するため、たとえば、4096 の初期バッファーがあり、それが使い果たされたら、戻り文字列用に 4096 を malloc してコピーし、バッファーへの読み取りを続けます。 (最初から)、さらに 1000 バイトが読み取られた場合は、5097 に再割り当てしてそれを返します。

バイトごとにアプローチしてヒープ割り当てを最小限に抑えることに夢中になるのは、初心者によくある間違いだと思います。KB 単位でも少し小さいです。システムはページ単位 (4 KB) を割り当てますが、それに合わせて調整することもできます。

*関数内のローカル ストレージ用に提供されるメモリ。

于 2012-08-22T14:56:30.187 に答える