tags:

views:

49

answers:

2

Hi all,

I'm fairly new to C so sorry if this is a stupid question but when I run the following code:

#include <stdio.h>

int main () {
    int i;
    int test[10];
    char string[81];

    for(i = 0; i < 10; i++){
        scanf("%d", &test[i]);
    }

    for(i=0; i < 7; i++){
        gets(string);
        printf("String was entered\n");
    }

}

And enter any 10 digits, the line "string was entered" will be printed even though I didn't enter a string in the command window. Can anyone explain why? Is there any way to stop it happening?

Thanks!

+4  A: 

After you read in data using scanf, the newline is still sitting in the input queue waiting to be read. gets reads that newline and stops (because it's reached the end of the line!)

Note that it's a bad idea to use gets: it provides no way to put a limit on how many characters get read into the buffer, so if you type in more characters than will fit in the buffer, you'll end up overflowing the buffer, resulting in data corruption, an application crash, a huge security vulnerability, and/or any number of other unpredictable results. For a safe alternative, you can use fgets instead with stdin:

fgets(string, sizeof(string), stdin);

(Note that you'd probably want to use a symbolic constant of some kind for the size of string so that you don't repeat it in multiple places - or use sizeof(string) when the array definition is visible.)

James McNellis
Thanks for the answer! Is there any way to clear the input queue so that gets (or fgets?) doesn't have anything to read?
Sam
@Sam: no, and if you're trying to clear it that probably means you're doing something wrong..
R..
@Sam: Interlacing calls to `fgets` and `scanf` can be... painful. :-) One way to handle it is just to use one or the other (and if you use `fgets`, you can use `sscanf` to parse individual lines, per RBerteig's suggestion.
James McNellis
Thanks again for the help. I'm doing a tutorial problem where we've been instructed to use scanf and gets functions to do something fairly (but a bit more complicated) similar to the code above. Not sure if the instructor just didn't realise that something like this would happen or if I'm doing something horribly wrong.
Sam
The instructor should be shot for having students use `gets` at all. `gets` is slated for removal in the next revision of the C standard, for good reason.
R..
@Jonathan: Thanks; I was debating whether it was a good idea to use `sizeof(string)`; that tends to be very confusing to beginners (why does it work here but not when you pass an array as a function argument?!), but I suppose everyone has to learn how that works some time.
James McNellis
+3  A: 

At a guess, scanf() didn't consume the newline that you had to type so that it could process the ten integers you wanted to get before the string. So, after the last call to scanf(), gets() is facing an input buffer that begins with a newline. Presto, it has met its spec so it copies nothing to its buffer and returns.

In general, scanf() and gets() are poor choices for new code. They both have issues that make them painful to use right, or even dangerous to use at all.

Specifically, gets() does not and cannot check its output buffer size, so it will readily overwrite whatever memory happens to be located after its buffer. That way lies corruption of global state or the stack. If it is the stack, then it is possible to exploit that to gain control of the program and make it execute arbitrary code. That is not a good thing.

It would be better to consume your input stream with fgets() which has a limit on its buffer size, and to parse it with sscanf() and other functions once read.

RBerteig