首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在realloc()中使用fget

在realloc()中使用fget
EN

Stack Overflow用户
提问于 2018-10-25 08:19:19
回答 2查看 2.3K关注 0票数 2

我试图创建一个函数,使用fgets()从文本文件中读取一行,并使用malloc()将其存储在动态分配char*中,但我不确定如何使用realloc(),因为我不知道这一行文本的长度,也不想猜测这一行可能最大大小的神奇数字。

代码语言:javascript
复制
#include "stdio.h"
#include "stdlib.h"
#define INIT_SIZE 50

void get_line (char* filename)

    char* text;
    FILE* file = fopen(filename,"r");

    text = malloc(sizeof(char) * INIT_SIZE);

    fgets(text, INIT_SIZE, file);

    //How do I realloc memory here if the text array is full but fgets
    //has not reach an EOF or \n yet.

    printf(The text was %s\n", text);

    free(text);

int main(int argc, char *argv[]) {
    get_line(argv[1]);
}

我正计划用文本行做其他事情,但为了保持简单,我只是打印了它,然后释放了内存。

另外:主函数是通过使用文件名作为第一个命令行参数来启动的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-10-25 08:40:37

吸气线函数是您所要寻找的。

像这样使用它:

代码语言:javascript
复制
char *line = NULL;
size_t n;
getline(&line, &n, stdin);

如果您真的想自己实现这个函数,可以编写如下内容:

代码语言:javascript
复制
#include <stdlib.h>
#include <stdio.h>

char *get_line()
{
    int c;
    /* what is the buffer current size? */
    size_t size = 5;
    /* How much is the buffer filled? */
    size_t read_size = 0;
    /* firs allocation, its result should be tested... */
    char *line = malloc(size);
    if (!line) 
    {
        perror("malloc");
        return line;
    }

    line[0] = '\0';

    c = fgetc(stdin);
    while (c != EOF && c!= '\n')
    {            
        line[read_size] = c;            
        ++read_size;
        if (read_size == size)
        {
            size += 5;
            char *test = realloc(line, size);
            if (!test)
            {
                perror("realloc");
                return line;
            }
            line = test;
        }
        c = fgetc(stdin);
    }
    line[read_size] = '\0';
    return line;
}
票数 4
EN

Stack Overflow用户

发布于 2018-10-25 09:27:00

有了void get_line (char* filename)的声明,您就永远无法使用在get_line函数之外读取和存储的行,因为您不会将指针返回到行,并且不会传递任何指针的地址,从而使调用函数中的任何分配和读取可见。

一个很好的模型(显示返回类型和有用的参数)用于将未知数目的字符读入单个缓冲区的函数总是POSIX getline。您可以使用fgetc of fgets和固定缓冲区实现自己的功能。只有在将所需的fgets调用数量最小化的情况下,效率才有利于使用realloc。(这两个函数将共享相同的低级别输入缓冲区大小,例如参阅gcc源IO_BUFSIZ常量-如果我记得,在最近的名称更改后,这个值现在是LIO_BUFSIZE,但基本上可以归结为Linux上的8192字节IO缓冲区和windows上的512字节)。

只要动态分配原始缓冲区(使用malloccallocrealloc),就可以使用固定缓冲区继续读取,使用fgets将读取的字符添加到分配的行中,并检查最后一个字符是'\n'还是EOF,以确定何时完成操作。只需在每次迭代时使用fgets读取一个固定值的字符缓冲区,并在每次迭代时将新字符追加到末尾,并在行中使用realloc

重新分配时,始终使用临时指针进行realloc。这样,如果内存用完,realloc返回NULL (或由于任何其他原因而失败),则不会用NULL创建内存泄漏覆盖指向当前分配块的指针。

使用为缓冲区大小定义的SZINIT (如果用户传递0)或用户为line分配初始存储所提供的大小(作为指向char指针的指针传递),然后根据需要重新分配,返回在成功时读取的字符数或失败时的-1 (与POSIX getline相同)的灵活实现可以这样做:

代码语言:javascript
复制
/** fgetline, a getline replacement with fgets, using fixed buffer.
 *  fgetline reads from 'fp' up to including a newline (or EOF)
 *  allocating for 'line' as required, initially allocating 'n' bytes.
 *  on success, the number of characters in 'line' is returned, -1
 *  otherwise
 */
ssize_t fgetline (char **line, size_t *n, FILE *fp)
{
    if (!line || !n || !fp) return -1;

#ifdef SZINIT
    size_t szinit = SZINIT > 0 ? SZINIT : 120;
#else
    size_t szinit = 120;
#endif

    size_t idx = 0,                 /* index for *line */
        maxc = *n ? *n : szinit,    /* fixed buffer size */
        eol = 0,                    /* end-of-line flag */
        nc = 0;                     /* number of characers read */
    char buf[maxc];     /* VLA to use a fixed buffer (or allocate ) */

    clearerr (fp);                  /* prepare fp for reading */
    while (fgets (buf, maxc, fp)) { /* continuall read maxc chunks */
        nc = strlen (buf);          /* number of characters read */
        if (idx && *buf == '\n')    /* if index & '\n' 1st char */
            break;
        if (nc && (buf[nc - 1] == '\n')) {  /* test '\n' in buf */
            buf[--nc] = 0;          /* trim and set eol flag */
            eol = 1;
        }
        /* always realloc with a temporary pointer */
        void *tmp = realloc (*line, idx + nc + 1);
        if (!tmp)       /* on failure previous data remains in *line */
            return idx ? (ssize_t)idx : -1;
        *line = tmp;    /* assign realloced block to *line */
        memcpy (*line + idx, buf, nc + 1);  /* append buf to line */
        idx += nc;                  /* update index */
        if (eol)                    /* if '\n' (eol flag set) done */
            break;
    }
    /* if eol alone, or stream error, return -1, else length of buf */
    return (feof (fp) && !nc) || ferror (fp) ? -1 : (ssize_t)idx;
}

(注意:,因为nc已经在buf中保存了当前的字符数,所以memcpy可以用来将buf的内容追加到*line中,而无需再次扫描终止的nul-字符),请查看并告诉我您是否还有其他问题。

从本质上说,您可以使用它作为POSIX getline的插入替代物(尽管它的效率不太高--但也不错)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52984551

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档