0

I have two inputs using fgets() function. Obviously, I declare size of input hoping it will truncate the input. It does truncate the input, but the remaining characters overflow into the following fgets(). I thought flushing the stdin would be the fix, but it doesn't seem to be working. Any help? Example below.

char a[3];
char b[3];
fgets(a, sizeof(a), stdin);
fflush(stdin);
fgets(b, sizeof(b), stdin);
fprintf(stderr, "%s%s", a, b);

an input of "help" followed by "ok" would produce the following:

hel
pok
cameron
  • 33
  • 5
  • Remember, to have a valid string in C, you need to think of the termination `\0` character. So if you truncate a string, you need to add the terminating character where the truncation happened. – Julien Thierry May 10 '20 at 16:17
  • 2
    You're better off reading the entire line, using the portion you want, and ignoring the rest. Using `fflush` on `stdin` is asking for trouble. – Tom Karzes May 10 '20 at 16:19
  • 1
    Does this answer your question? [I am not able to flush stdin](https://stackoverflow.com/questions/2187474/i-am-not-able-to-flush-stdin) – Adrian Mole May 10 '20 at 16:19
  • @AdrianMole That's explained why fflush won't work, however It doesn't explain how I would get around the overflow. Thank you though – cameron May 10 '20 at 16:23
  • @TomKarzes Because the inputs in my case could potentially have spaces, I can't read everything off one line otherwise it would be impossible to tell which is which. – cameron May 10 '20 at 16:25
  • @JulienThierry That makes sense, but the truncation is done within the fgets() function, so how would I add the terminating character before it's too big? – cameron May 10 '20 at 16:26
  • 1
    @cameron Read the entire line, then look for the spaces. It's not hard to do. I'm telling you you're going to have problems flushing `stdin`. You will end up losing data that you want. – Tom Karzes May 10 '20 at 16:29
  • @TomKarzes I understand what you're saying and I realise fflush is a bad idea, but I can't scan for spaces because some inputs have spaces within them. – cameron May 10 '20 at 16:32
  • @cameron Ok, but the point is that whatever you want to use to determine the end of the input can be done more reliably if you have the entire line in a buffer. If you want to use a fixed character count, you can. If you don't want to look for spaces, you don't have to. It is strictly more powerful than cutting off the input after 2 characters and then blindly discarding anything left over. – Tom Karzes May 10 '20 at 16:34
  • @cameron Alternatively, you could read `stdin` one character at a time with `getchar()`. Just don't try to flush your input stream. – Tom Karzes May 10 '20 at 16:37
  • Well, be sensible and allocate a buffer that is a bit more useful than `char a[3];` Given that there will be a newline and a string terminator for a well-formed input that's just one character in the message. Try `char a[1000];` If a user overflows that, then they are fooling around anyway. – Weather Vane May 10 '20 at 17:10
  • @WeatherVane That actually makes a lot of sense. although i'm getting this buffer overflow, does the actual value for the variables remain what I intended, just the output is n't correct, or does the buffer overflow affect the variable itself? – cameron May 10 '20 at 17:19
  • There won't be any buffer overflow if you tell `fgets` what size it is. If the input string length is the full buffer (999 here) then you know the user is fooling, so why should you care if the input was longer? If it is shorter, there wasn't any truncated remaining in the input. – Weather Vane May 10 '20 at 17:23

2 Answers2

1

strchr could be used to look for a newline. If found, set the newline to zero to terminate the string. Call fgets to fill the remainder of the array. The loops continue until both arrays are filled.
The array with size [4] can store three characters and a terminating zero.

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

int main ( void) {
    char a[4];
    char b[4];
    char *newline = NULL;
    size_t len = 0;

    fgets(a, sizeof(a), stdin);
    while ( ( newline = strchr ( a, '\n'))) {//find a newline
        *newline = 0;//set terminating zero
        len = strlen ( a);
        if ( len < sizeof a - 1) {//space available in array
            fgets ( newline, sizeof a - len, stdin);//more input into array
        }
        else {
            break;
        }
    }

    fgets(b, sizeof(b), stdin);
    while ( ( newline = strchr ( b, '\n'))) {//find a newline
        *newline = 0;//set terminating zero
        len = strlen ( b);
        if ( len < sizeof b - 1) {//space available in array
            fgets ( newline, sizeof b - len, stdin);//more input into array
        }
        else {
            break;
        }
    }

    fprintf(stderr, "%s%s\n", a, b);
    return 0;
}

getchar could be used to clear the input stream if the first array does not contain a newline.

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

int main ( void) {
    char a[4];
    char b[4];

    fgets(a, sizeof(a), stdin);
    if ( ! strchr ( a, '\n')) {//no newline
        while ( '\n' != getchar ( )) {//clear the input stream
            if ( EOF == getchar ( )) {
                fprintf ( stderr, "problem EOF\n");
                return 1;
            }
        }
    }

    fgets(b, sizeof(b), stdin);

    fprintf(stderr, "%s%s\n", a, b);
    return 0;
}
user3121023
  • 8,181
  • 5
  • 18
  • 16
  • Thanks for the response. This logically makes sense to me, but when I compile it (GCC linux) and run it. If I enter more than 4 characters for a, the left over characters are transferred to B. Like "overflowing" onto b. This is the issue I am having. if you compile this do you get the same outcome? – cameron May 10 '20 at 21:05
  • Yes, I would expect hel in a and ok in b. That's what I want. Essentially. When the first input is truncated due to being too big, I don't wish for the remainder to be passed on to the second array. But instead to simply delete. – cameron May 10 '20 at 21:25
  • Wow that actually worked you god. Thank you. I'm a little confused on the newline part. So if there is a space left at the end of the array, lets say a, the fgets() will leave a newline in it's place? If so, this makes sense. – cameron May 10 '20 at 21:45
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/213578/discussion-between-cameron-and-user3121023). – cameron May 10 '20 at 22:00
0

how to flush stdin

Do NOT use: fflush( stdin )

The function: fflush() is ONLY for output streams and the C programming language specifically states that calling fflush() with an input stream results in undefined behavior. (regardless of what visual studio might allow)

Suggest:

int ch;
while( (ch = getchar() ) != EOF && ch != '\n' ){;}

regarding the function: fgets()

That function always appends a NUL byte to the input and always stops 1 short of the length it is given, so there will be room for the NUL byte

regarding:

char a[3];
char b[3];
fgets(a, sizeof(a), stdin);
fflush(stdin);
fgets(b, sizeof(b), stdin);
fprintf(stderr, "%s%s", a, b)

replace:

fflush(stdin);

with:

int ch;
while( ( ch = getchar() ) != EOF && ch != '\n' ){;}
user3629249
  • 16,402
  • 1
  • 16
  • 17