将fgets与realloc()一起使用
我试图创建一个函数,使用将fgets与realloc()一起使用,c,malloc,realloc,C,Malloc,Realloc,我试图创建一个函数,使用fgets()从文本文件中读取一行,并使用malloc()将其存储在动态分配的字符*中,但我不确定如何使用realloc()因为我不知道这一行文字的长度,也不想猜测这一行可能达到的最大大小的神奇数字 #include "stdio.h" #include "stdlib.h" #define INIT_SIZE 50 void get_line (char* filename) char* text; FILE* file = fopen(filena
fgets()
从文本文件中读取一行,并使用malloc()
将其存储在动态分配的字符*中,但我不确定如何使用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]);
}
我计划用这行文字做其他事情,但为了保持简单,我刚刚打印了它,然后释放了内存
另外:主函数是通过使用文件名作为第一个命令行参数来启动的。一个可能的解决方案是使用两个缓冲区:一个临时缓冲区,在调用
fgets
时使用;以及重新分配并附加临时缓冲区的缓冲区
也许是这样的:
char temp[INIT_SIZE]; // Temporary string for fgets call
char *text = NULL; // The actual and full string
size_t length = 0; // Current length of the full string, needed for reallocation
while (fgets(temp, sizeof temp, file) != NULL)
{
// Reallocate
char *t = realloc(text, length + strlen(temp) + 1); // +1 for terminator
if (t == NULL)
{
// TODO: Handle error
break;
}
if (text == NULL)
{
// First allocation, make sure string is properly terminated for concatenation
t[0] = '\0';
}
text = t;
// Append the newly read string
strcat(text, temp);
// Get current length of the string
length = strlen(text);
// If the last character just read is a newline, we have the whole line
if (length > 0 && text[length - 1] == '\n')
{
break;
}
}
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;
}
[Discalimer:上面的代码未经测试,可能包含bug]该函数正是您需要的
像这样使用它:
char temp[INIT_SIZE]; // Temporary string for fgets call
char *text = NULL; // The actual and full string
size_t length = 0; // Current length of the full string, needed for reallocation
while (fgets(temp, sizeof temp, file) != NULL)
{
// Reallocate
char *t = realloc(text, length + strlen(temp) + 1); // +1 for terminator
if (t == NULL)
{
// TODO: Handle error
break;
}
if (text == NULL)
{
// First allocation, make sure string is properly terminated for concatenation
t[0] = '\0';
}
text = t;
// Append the newly read string
strcat(text, temp);
// Get current length of the string
length = strlen(text);
// If the last character just read is a newline, we have the whole line
if (length > 0 && text[length - 1] == '\n')
{
break;
}
}
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;
}
如果你真的想自己实现这个函数,你可以这样写:
char temp[INIT_SIZE]; // Temporary string for fgets call
char *text = NULL; // The actual and full string
size_t length = 0; // Current length of the full string, needed for reallocation
while (fgets(temp, sizeof temp, file) != NULL)
{
// Reallocate
char *t = realloc(text, length + strlen(temp) + 1); // +1 for terminator
if (t == NULL)
{
// TODO: Handle error
break;
}
if (text == NULL)
{
// First allocation, make sure string is properly terminated for concatenation
t[0] = '\0';
}
text = t;
// Append the newly read string
strcat(text, temp);
// Get current length of the string
length = strlen(text);
// If the last character just read is a newline, we have the whole line
if (length > 0 && text[length - 1] == '\n')
{
break;
}
}
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;
}
#包括
#包括
char*get_line()
{
INTC;
/*缓冲区的当前大小是多少*/
尺寸=5;
/*缓冲区填满了多少*/
大小\u t读取\u大小=0;
/*第一次分配,其结果应进行测试*/
char*line=malloc(大小);
如果(!行)
{
佩罗尔(“马洛克”);
回流线;
}
第[0]行=“\0”;
c=fgetc(标准偏差);
而(c!=EOF&&c!='\n')
{
行[读取大小]=c;
++读取大小;
如果(读取大小==大小)
{
尺寸+=5;
char*test=realloc(行、大小);
如果(!测试)
{
perror(“realloc”);
回流线;
}
直线=测试;
}
c=fgetc(标准偏差);
}
行[读取大小]='\0';
回流线;
}
声明为无效获取行(char*filename)
,您永远不能使用在get\u line
函数之外读取和存储的行,因为您不会返回指向行的指针,也不会传递任何指针的地址,而这可能会使任何分配和读取在调用函数中变为可见
POSIXgetline
始终是任何函数将未知数量的字符读入单个缓冲区的好模型(显示返回类型和有用参数)。您可以使用fgets
的fgetc
和固定缓冲区来实现自己的功能。效率有利于使用fgets
,只要它能最大限度地减少所需的realloc
调用次数。(这两个函数将共享相同的低级输入缓冲区大小,例如,请参见gcc sourceIO_BUFSIZ
constant——如果我回忆起来,在最近的名称更改之后,它现在是LIO_BUFSIZE
,但基本上可以归结为Linux上的8192
字节IO缓冲区和windows上的512
字节)
只要动态分配原始缓冲区(使用malloc
、calloc
或realloc
),您可以使用固定缓冲区连续读取,方法是使用fgets
将读取到固定缓冲区的字符添加到分配行,并检查最后一个字符是'\n'
还是EOF
,以确定何时完成。只需在每次迭代时使用fgets
和realloc
读取一个固定缓冲区大小的字符,并在末尾添加新字符
重新分配时,始终使用临时指针realloc
。这样,如果内存不足并且realloc
返回NULL
(或由于任何其他原因失败),则不会用NULL
覆盖指向当前分配块的指针,从而造成内存泄漏
一种灵活的实现,它使用定义的缓冲区大小的SZINIT
(如果用户通过0
)或用户提供的大小将固定缓冲区大小调整为VLA,以分配行的初始存储(作为指向字符的指针通过),然后根据需要重新分配,成功时返回读取的字符数或失败时返回读取的字符数(与POSIXgetline
相同),操作如下:
/** 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
的内容附加到*行
,而无需再次扫描终止的nul字符)请仔细查看,如果有进一步的问题,请告诉我
基本上,您可以使用它作为POSIXgetline
的替代品(虽然效率不高,但也不错)根据代码中的注释,您对初始缓冲区太短的情况感兴趣,对吗?请查看。我猜你基本上就是想要这样。阅读一行无限长的文字有一个缺点,那就是允许极端代理压倒系统资源——不要成为黑客的目标。有一个合理的上限是防御性的编码。你不喜欢一种只允许你做string line=Console.ReadLine()
的语言吗?请注意getline
是一个只支持POSIX的函数,它不可移植。@Someprogrammerdude的“POSIX”和“not portable”在术语上有些矛盾。只有当“不可移植”实际上意味着“几乎在任何地方都可用,但在Windows上不可用”时,这才是正确的代码>从不realloc
指针本身,而是使用临时指针,例如void*tmp=realloc(行、大小)
@DavidC.Rankin我同意,但请注意,如果realloc
失败,则调用exit()
是的,这是处理发生故障(或