我有一个简单的函数,它应该从标准输入读取行并将其放入一个字符数组中,我循环调用这个函数,直到输入 EOF。问题是,对于极长的行(超过 10k 个字符), fgets 只读取一些字符并停止,尽管它没有遇到任何\n 并且缓冲区有足够的空间,因此下次调用此函数会读取其余部分的线。这种行为是否有原因(错误编写的代码,我不知道的一些缓冲区)?可以修复吗?如果我的代码有问题,请指出,我将不胜感激。
static int getLine(char** line){
if(feof(stdin)) return 0;
int len=0;
char* pointer=NULL;
int max = 1;
while(1){
max+=400;
*line=(char*)realloc( *line,max);
if(pointer==NULL)
pointer=*line;
if(fgets(pointer, 401, stdin)==NULL)break;
int len1=strlen(pointer);
len+=len1;
if(len1!=400 || pointer[len1]=='\n')break;
pointer+=len1;
}
if(len==0)return 0;
if((*line)[len-1]=='\n'){
*line=(char*)realloc(*line, len);
(*line)[len-1]='\0';
return len-1;}//without \n
return len;
}
最佳答案
我认为您的问题可能是您使用指针
的方式:
char* pointer=NULL;
int max = 1;
while(1){
max+=400;
*line=(char*)realloc( *line,max);
if(pointer==NULL)
pointer=*line;
if(fgets(pointer, 401, stdin)==NULL)
break;
int len1=strlen(pointer);
len+=len1;
if(len1!=400 || pointer[len1]=='\n')
break;
pointer+=len1;
}
问题在于 realloc()
可以更改数据的存储位置,但您可以将其修复到最初指定的位置。如果您处理大量数据,则更有可能在重新分配时移动数据。您可以通过跟踪 *line
的值来诊断此问题(在每次迭代的 realloc()
之后打印它)。
解决方法相当简单:使用偏移量而不是指针作为权威长度,并在每次迭代时设置pointer
:
enum { EXTRA_LEN = 400 };
size_t offset = 0;
int max = 1;
while (1)
{
max += EXTRA_LEN;
char *space = (char*)realloc(*line, max); // Leak prevention
if (space == 0)
return len;
*line = space;
char *pointer = *line + offset;
if (fgets(pointer, EXTRA_LEN + 1, stdin) == NULL)
break;
int len1 = strlen(pointer);
len += len1;
if (len1 != EXTRA_LEN || pointer[len1] == '\n')
break;
offset += len1;
}
我对在调用 fgets()
时使用 401 而不是 400 持保留态度,但我没有精力去确定它是否正确。我已经对您的代码进行了尽可能少的更改;如果这是我正在完善的代码,我可能会进行更广泛的更改。 (特别是,max
将从 0 开始,而不是 1,而且我不会在调用 fgets()
时使用 +1。
关于c - fgets 不读取整行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27152451/