简体   繁体   中英

Reading a Line From File using fgets

What should be incredible simple has me stumped. All I am doing is writing a getLine method that should read a line into a buffer. I allocate memory to the buffer starting at 10 bytes , then fgets into a char array. The idea is that I attempt this over and over, doubling the size of the buffer, until it gets the whole line. However what I seem to be observing is that it reads a portion of the line, and then on the next attempt continues where it ran out of room on the last attempt, so it gives the last part of the line. Any insight it to what is wrong, I expect with my realloc memory to the buffer, would be much appreciated.

char * mygetline( char **buffer,  FILE * infile )
{
    int buffSiz = 10;
    *buffer = calloc( buffSiz, 1 );
    do
    {
        char * result = fgets(*buffer, sizeof *buffer ,infile);
        if(result == NULL)
        {
            free(buffer);
            return NULL;
        }

        if(strchr(*buffer, '\n'))
            return *buffer;
        else
        {
            char *newBuf;
            buffSiz = buffSiz*2;
            newBuf = realloc(NULL, buffSiz);
            char *buffer = newBuf;
            printf("%d", buffSiz);
            printf("%s", *buffer);
        }
    } while (1);  // INFINITE LOOP - WE ONLY GET OUT BY RETURNING FROM WITHIN

There are multiple flaws:

  • sizeof *buffer doesn't do what you want since it's a pointer. You should use buffSiz instead

  • char *buffer = newBuf; you're assigning the new memory to a local variable, ie a variable that disappears when the else is exited

  • you're not passing your buffer to realloc , you're always passing NULL

  • you're not checking the return of realloc

As a shameless self-promotion, here's a function I posted in another answer .

That's how the file functions works. You have to get the file position at the start, then reset the position every time you attempt a new read.

You can get the current position with the ftell function, and then set the position with the fseek function.


Instead of doing that (getting position and constant repositioning the file position), why not use the fact that realloc reallocates the passed in buffer and keeps the contents together with the fact that the read functions reads the next part? In that case you need to have a pointer to where to read next, and if no newline then just reallocate and advance the pointer?

Something like this:

char *readpos = *buffer;
size_t readsize = bufSize;

while (1)
{
    char *p = fgets(readpos, readsize, infile);
    if (!p)
        break;  /* Error */

    /* Search from the end, as there's where the newline should be */
    if (strrchr(p, '\n') != NULL)
        return *buffer;  /* Found the newline */

    /* Need to allocate more memory */
    bufSize += bufsize;
    *buffer = realloc(*buffer, bufSize);

    /* Set the pointer to next position to read into */
    readpos = *buffer + strlen(buffer);

    /* Loop takes case of trying again */
}

Note: The above code was written in the browser, not tested, and might need some tuning to make it work properly.

realloc期望将需要重新分配的缓冲区作为其第一个参数。

realloc(*buffer, buffSiz);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM