问题
I have a simple function, which is supposed to read line from standard input and put it into an char array, and I call this function in a loop till EOF is inputed. The problem is, that for extremely long lines (more than 10k characters) the fgets reads only a number of characters and stops, although it has not encountered any \n and the buffer has sufficient space, therefore next invoking of this function reads the rest of the line. Is there a reason for this behaviour (wrongly written code, some buffers I am unavare of)? Is it possible to fix it? If I have something wrong in the code I will be gratefull if you point it out.
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;
}
回答1:
I think it likely that your problem is the way you use pointer
:
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;
}
The trouble is that realloc()
can change where the data is stored, but you fix it to the location you are first given. It is more likely that you'll have data move on reallocation if you handle large quantities of data. You can diagnose this by tracking the value of *line
(print it after the realloc()
on each iteration).
The fix is fairly simple: use an offset instead of a pointer as the authoritative length, and set pointer
on each iteration:
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;
}
I have reservations about the use of 401 rather than 400 in the call to fgets()
, but I haven't the energy to expend establishing whether it is correct or not. I've done about the minimum changes to your code that I can; I would probably make more extensive changes if it were code I was polishing. (In particular, max
would start at 0, not 1, and I would not use the +1 in the call to fgets()
.
来源:https://stackoverflow.com/questions/27152451/fgets-not-reading-whole-line