我试图创建一个函数,使用fgets()从文本文件中读取一行,并使用malloc()将其存储在动态分配char*中,但我不确定如何使用realloc(),因为我不知道这一行文本的长度,也不想猜测这一行可能最大大小的神奇数字。
#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]);
}我正计划用文本行做其他事情,但为了保持简单,我只是打印了它,然后释放了内存。
另外:主函数是通过使用文件名作为第一个命令行参数来启动的。
发布于 2018-10-25 08:40:37
吸气线函数是您所要寻找的。
像这样使用它:
char *line = NULL;
size_t n;
getline(&line, &n, stdin);如果您真的想自己实现这个函数,可以编写如下内容:
#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;
}发布于 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字节)。
只要动态分配原始缓冲区(使用malloc、calloc或realloc),就可以使用固定缓冲区继续读取,使用fgets将读取的字符添加到分配的行中,并检查最后一个字符是'\n'还是EOF,以确定何时完成操作。只需在每次迭代时使用fgets读取一个固定值的字符缓冲区,并在每次迭代时将新字符追加到末尾,并在行中使用realloc。
重新分配时,始终使用临时指针进行realloc。这样,如果内存用完,realloc返回NULL (或由于任何其他原因而失败),则不会用NULL创建内存泄漏覆盖指向当前分配块的指针。
使用为缓冲区大小定义的SZINIT (如果用户传递0)或用户为line分配初始存储所提供的大小(作为指向char指针的指针传递),然后根据需要重新分配,返回在成功时读取的字符数或失败时的-1 (与POSIX getline相同)的灵活实现可以这样做:
/** 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的插入替代物(尽管它的效率不太高--但也不错)
https://stackoverflow.com/questions/52984551
复制相似问题