-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 的字符并将它们存储到 . 指向的缓冲区中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 回答
0

为什么没有人提议将缓冲区从堆移动到堆栈?这是我现在的解决方案:

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;
}
于 2013-02-13T12:58:28.190 回答