与fgets不读整条生产线 [英] fgets not reading whole line

查看:133
本文介绍了与fgets不读整条生产线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的功能,这是应该从标准输入读取行,并把它变成一个字符数组,我呼吁在一个循环,直到EOF这个功能便被输入。问题是,对于非常长的行(超过10,000个字符)与fgets只读取字符数和停止时,虽然没有遇到\\ n和缓冲区有足够的空间,这个功能的,因此下一次调用读取休息的线。是否有此行为的原因(误写成code,有的缓冲区我unavare的)?是否有可能解决这个问题?如果我有什么不对的code,如果你指出来我会gratefull。

 静态INT函数getline(字符**线){
    如果(的feof(标准输入))返回0;
    INT LEN = 0;
    字符*指针= NULL;
    INT最大= 1;
    而(1){
        MAX + = 400;
        *行=(字符*)的realloc(*线,最大值);
        如果(指针== NULL)
            指针= *线;
        如果(与fgets(指针,401,标准输入)== NULL)破​​;
        INT LEN1 = strlen的(指针);
        LEN + = LEN1;
        如果(LEN1 = 400 ||指针[LEN1] =='\\ n'!)打破;
        指针+ = LEN1;
    }
    如果(LEN == 0)返回0;
    如果((*行)[LEN-1] =='\\ n'){
    *行=(字符*)的realloc(*线,LEN);
    (*行)[LEN-1] ='\\ 0';
    返回LEN-1;} //没有\\ n
    返回LEN;
}


解决方案

我认为这可能是你的问题是你使用的方式指针

 的char *指针= NULL;
INT最大= 1;
而(1){
    MAX + = 400;
    *行=(字符*)的realloc(*线,最大值);
    如果(指针== NULL)
        指针= *线;
    如果(与fgets(指针,401,标准输入)== NULL)
        打破;
    INT LEN1 = strlen的(指针);
    LEN + = LEN1;
    如果(LEN1!= 400 ||指针[LEN1] =='\\ n')
        打破;
    指针+ = LEN1;
}

麻烦的是,的realloc()可以改变数据存储的位置,但你把它固定在你第一次给定的位置。它更可能是你对重新分配数据移动,如果你处理大量的数据。您可以通过跟踪的价值诊断此 *行(即的realloc()在每次迭代后打印)。

解决方法是相当简单:用一个偏移量,而不是一个指针作为权威的长度,并设置指针在每次迭代:

 枚举{EXTRA_LEN = 400};
为size_t偏移= 0;
INT最大= 1;
而(1)
{
    MAX + = EXTRA_LEN;
    字符*空间=(的char *)realloc的(*线,最大值); //泄漏prevention
    如果(空== 0)
        返回LEN;
    *行=空间;
    字符*指针= *线+偏移;
    如果(与fgets(指针,EXTRA_LEN + 1,标准输入)== NULL)
        打破;
    INT LEN1 = strlen的(指针);
    LEN + = LEN1;
    如果(LEN1!= EXTRA_LEN ||指针[LEN1] =='\\ n')
        打破;
    胶印+ = LEN1;
}

我有关于在呼叫使用401,而不是400保留与fgets(),但我没有精力耗费确定它是否是正确的或不。我已经做了关于你的code,我可以最小的变化;如果它是code我被抛光我可能会做出更广泛的变化。 (特别是最大将在0开始,而不是1,我也不会在通话使用+1 与fgets()

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;
}

解决方案

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().

这篇关于与fgets不读整条生产线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆