读取输入的动态缓冲区大小

时间:2018-02-22 21:56:31

标签: c dynamic size buffer

我正在尝试创建一个程序,它将从stdin逐行读取,搜索该行以查找给定单词的开头和结尾,并输出所有匹配的单词。这是代码:

int main()
{
    char buffer[100];
    char **words = NULL;
    int word_count = 0;

    while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        int length = strlen(buffer);
        if (buffer[length - 1] == '\n') {
            word_count = count_words(buffer, FIRSTCHAR);
            if (word_count > 0) {
                words = get_words(buffer, FIRSTCHAR, LASTCHAR);
                for (int i = 0; i < word_count; ++i) {
                    printf("%s\n", words[i]);
                    free(words[i]);
                }
                free(words);
            }
        }
    }
    return 0;
}

我的基本功能正常运行,但我依赖于具有固定缓冲区大小的fgets()。 我想要的是动态分配一个内存缓冲区,其大小基于每一行的长度。

我只能看到解决它的一种方法,即用 fgetc 迭代输入并递增计数器直到行结束并使用该计数器代替 sizeof(缓冲区),但我不知道如何让fgetc读取正确的相关行。

有没有聪明的方法来解决这个问题?

2 个答案:

答案 0 :(得分:2)

  

但我依赖fgets()来获得固定的缓冲区大小。我想要的是动态分配一个内存缓冲区,其大小基于每行的长度

我确实为另一个SO答案编写了fgets版本,该答案读取整行并返回一个 malloc已分配指针与整行的内容。这是 代码:

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

char *fgets_long(FILE *fp)
{
    size_t size = 0, currlen = 0;
    char line[1024];
    char *ret = NULL, *tmp;

    while(fgets(line, sizeof line, fp))
    {
        int wholeline = 0;
        size_t len = strlen(line);

        if(line[len - 1] == '\n')
        {
            line[len-- - 1] = 0;
            wholeline = 1;
        }

        if(currlen + len >= size)
        {
            // we need more space in the buffer
            size += (sizeof line) - (size ? 1 : 0);
            tmp = realloc(ret, size);
            if(tmp == NULL)
                break; // return all we've got so far
            ret = tmp;
        }

        memcpy(ret + currlen, line, len + 1);
        currlen += len;

        if(wholeline)
            break;
    }

    if(ret)
    {
        tmp = realloc(ret, currlen + 1);
        if(tmp)
            ret = tmp;
    }

    return ret;
}

诀窍是检查是否读取了换行符。如果它被阅读,那么你可以 返回缓冲区,否则重新分配缓冲区sizeof line 字节并将其附加到缓冲区。如果你愿意,你可以使用这个功能。

如果您正在使用POSIX系统和/或正在使用GNU GCC进行编译,则可以选择其他方式 也可以使用getline

void foo(FILE *fp)
{
    char *line = NULL;
    size_t len = 0;

    if(getline(&line, &len, fp) < 0)
    {
        free(line); // man page says even on failure you should free
        fprintf(stderr, "could not read whole line\n");
        return;
    }

    printf("The whole line is: '%s'\n", line);

    free(line);

    return;
}

答案 1 :(得分:0)

功能:getline()可以满足您的需求。语法:

ssize_t getline(char **lineptr, size_t *n, FILE *stream);

该函数在stdio.h头文件中公开,通常需要:#define _POSIX_C_SOURCE 200809L#define _GNU_SOURCE作为调用getline()的文件中的第一行

强烈建议阅读/理解MAN页面的“getline()”以获取所有肮脏的细节。