簡體   English   中英

C-如何從Stdin或文件內存保存中讀取字符串行

[英]C - How to Read String Lines from Stdin or File Memory Save

我需要讀取行的版本可以節省內存。 我有這個“工作”的解決方案。 但是我不確定它在內存中的行為。 當我啟用free(text)它可以工作幾行,然后出現錯誤。 因此,盡管我分配了文本,但現在文本和結果都不會被釋放。 那是對的嗎 ? 為什么會這樣呢?

#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;
}

我有很多短行需要閱讀,我還需要stdin可以用FILE*句柄替換。 因為我只有幾行,所以不需要重新分配文本。

fgets返回指向字符串的指針,因此在fgets行之后, result將與text相同。 然后當您撥打free (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可能是明智的選擇,這樣內存就不會碎片化,並且它也應該更快。

char *fgets(char *s, int size, FILE *stream) char *fgets(char *s, int size, FILE *stream) 讀取最多小於大小的字符,並將其存儲到s指向的緩沖區中。 在EOF或換行符之后停止讀取。 如果讀取換行符,則將其存儲到緩沖區中。 終止空字節( '\\0' )存儲在緩沖區中的最后一個字符之后。

返回值成功則返回s ,錯誤則返回NULL ,或者在未讀取任何字符的情況下返回文件結尾。

因此,您的代碼存在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;
    }
}

然后此函數的調用者應負責釋放該函數的返回值指向的內存。

我知道您提到過,這些行只是短而已,但是所提供的解決方案都不適用於長度大於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字節的固定緩沖區進行操作。 但是,這需要對該問題有更全面的了解。 一旦實現,采用這種解決方案將獲得最佳解決方案。

#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);
}

為什么沒有人提議將緩沖區從堆移動到堆棧? 現在這是我的解決方案:

char input[1024]; // held ready as buffer for fgets

char* readFromIn()
{
    char* result = fgets(input, 1024, stdin);
    if (result == null)
        return "";
    if (result[strlen(result) - 1] == '\n')
        result[strlen(result) - 1] = 0;
    return result;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM