-1

メモリを節約できる読み取り行のバージョンが必要です。私はこの「実用的な」ソリューションを持っています。しかし、それがメモリでどのように動作するかはわかりません。有効free(text)にすると、数行で機能し、エラーが発生します。したがって、テキストをmallocしても、テキストも結果も解放されません。あれは正しいですか ?そして、それはなぜですか?

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

char* readFromIn()
{
    char* text = malloc(1024);
    char* result = fgets(text, 1024, stdin);
    if (result[strlen(result) - 1] == 10)
        result[strlen(result) - 1] = 0;
    //free(text);
    return result;
}

これで読む短い行がたくさんあります。また、標準入力をFILE*ハンドルに置き換える必要があります。短い行しかないので、テキストを再割り当てする必要はありません。

4

5 に答える 5

2

fgetsは文字列へのポインタを返すため、fgets行の後resultは と同じメモリ アドレスになりますtext。次に、呼び出すfree (text);と、無効なメモリが返されます。

終了したら、呼び出し関数でメモリを解放する必要がありますresult

次のようなバッファを渡すようにコードを構成することで、malloc/free を回避することもできます。

void parent_function ()
{
    char *buffer[1024];

    while (readFromIn(buffer)) {
        // Process the contents of buffer
    }
}

char *readFromIn(char *buffer)
{
    char *result = fgets(buffer, 1024, stdin);
    int len;

    // fgets returns NULL on error of end of input,
    // in which case buffer contents will be undefined
    if (result == NULL) {
        return NULL;
    }

    len = strlen (buffer);
    if (len == 0) {
        return NULL;
    }

    if (buffer[len - 1] == '\n') {
        buffer[len - 1] = 0;

    return buffer;
}

malloc/free を回避しようとすることは、メモリが断片化されず、高速になるように、多くの小さくて寿命の短いアイテムを扱う場合におそらく賢明です。

于 2013-02-13T10:59:57.823 に答える
1

char *fgets(char *s, int size, FILE *stream) ストリームから size 文字未満の最大 1 文字を読み取り、 が指すバッファに格納しますs。EOF または改行の後、読み取りは停止します。改行が読み取られると、バッファに格納されます。'\0'バッファ内の最後の文字の後に、終端のヌル バイト ( ) が格納されます。

戻り:成功時、エラー時、または文字が読み取られずにファイルの終わりが発生した場合に戻ります。sNULL

したがって、コードには 2 つの重大な問題があります。

  1. の戻り値をチェックしませんfgets
  2. この文字列が格納されているメモリの割り当てを解除し、このメモリへのポインターを返します。このようなポインター (ダングリング ポインター) が指すメモリにアクセスすると、未定義の動作が発生します。

関数は次のようになります。

public char* readFromIn() {
    char* text = malloc(1024);
    if (fgets(text, 1024, stdin) != NULL) {
        int textLen = strlen(text);
        if (textLen > 0 && text[textLen - 1] == '\n')
            text[textLen - 1] == '\0';     // getting rid of newline character
        return text;
    }
    else {
        free(text);
        return NULL;
    }
}

この関数の呼び出し元は、この関数の戻り値が指すメモリの割り当てを解除する必要があります。

于 2013-02-13T11:15:58.877 に答える
1

行が短いだけだとおっしゃいましたが、提供されているソリューションはいずれも、長さが 1024 を超える行では機能しません。このため、行全体を読み取ろうとするソリューションを提供し、十分なスペースがない場合はバッファーのサイズを変更します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MINIMUM_CAPACITY 16

size_t read_line(char **buffer, size_t *capacity) {
    char *buf = *buffer;
    size_t cap = *capacity, pos = 0;

    if (cap < MINIMUM_CAPACITY) { cap = MINIMUM_CAPACITY; }

    for (;;) {
        buf = realloc(buf, cap);
        if (buf == NULL) { return pos; }
        *buffer = buf;
        *capacity = cap;

        if (fgets(buf + pos, cap - pos, stdin) == NULL) {
            break;
        }

        pos += strcspn(buf + pos, "\n");
        if (buf[pos] == '\n') {
            break;
        }

        cap *= 2;
    }

    return pos;
}

int main(void) {
    char *line = NULL;
    size_t size = 0;

    for (size_t end = read_line(&line, &size); line[end] == '\n'; end = read_line(&line, &size)) {
        line[end] = '\0'; // trim '\n' off the end
        // process contents of buffer here
    }

    free(line);
    return 0;
}

理想的なソリューションは、1 バイトの固定バッファで動作できるはずです。ただし、これには問題をより包括的に理解する必要があります。いったん達成されれば、そのような解決策を適応させることで、最適な解決策が達成されます。

于 2013-02-13T12:56:22.950 に答える
0
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *readFromIn(FILE *fp)
{
    char text[1024];
    size_t len;

    if (!fgets(text, sizeof text, fp)) return NULL;
    len = strlen(text);

    while (len && text[len-1] == '\n') text[--len] = 0;

    return strdup(text);
}
于 2013-02-13T11:17:23.883 に答える