Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

c - How to read input of unknown length using fgets

How am I supposed to read long input using fgets(), I don't quite get it.

I wrote this

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char buffer[10];
    char *input;
    while (fgets(buffer,10,stdin)){
        input = malloc(strlen(buffer)*sizeof(char));
        strcpy(input,buffer);
    }
    printf("%s [%d]",input, (int)strlen(input));
    free(input);
    return 0;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char buffer[10];
    char *input = 0;
    size_t cur_len = 0;
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        size_t buf_len = strlen(buffer);
        char *extra = realloc(input, buf_len + cur_len + 1);
        if (extra == 0)
            break;
        input = extra;
        strcpy(input + cur_len, buffer);
        cur_len += buf_len;
    }
    printf("%s [%d]", input, (int)strlen(input));
    free(input);
    return 0;
}

This is about the minimal set of changes that will give you the complete line of input. This grows the space by up to 9 bytes at a time; that isn't the best way to do it, but there's extra bookkeeping involved doing it the better ways (doubling the space allocated, and keeping a record of how much is allocated vs how much is in use). Note that cur_len record the length of the string in the space pointed to by input excluding the terminal null. Also note that the use of extra avoids a memory leak on failure to allocate.

The strcpy() operation could be legitimately replaced by memmove(input + cur_len, buffer, buf_len + 1) (and in this context, you could use memcpy() instead of memmove(), but it doesn't always work while memmove() does always work, so it is more reliable to use memmove()).


With length-doubling — the cur_max variable records how much space is allocated, and cur_len records how much space is in use.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char buffer[10];
    char *input = 0;
    size_t cur_len = 0;
    size_t cur_max = 0;
    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        size_t buf_len = strlen(buffer);
        if (cur_len + buf_len + 1 > cur_max)
        {
            size_t new_len = cur_max * 2 + 1;
            if (buf_len + 1 > new_len)
                new_len = buf_len + 1;
            char *extra = realloc(input, new_len);
            if (extra == 0)
                break;
            input = extra;
            cur_max = new_len;
        }
        strcpy(input + cur_len, buffer);
        cur_len += buf_len;
    }
    printf("%s [%d]", input, (int)strlen(input));
    free(input);
    return 0;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...