7

I need to do something like the following:

int main(void) {
char a,b,cstring;

printf("please enter something");
scanf("%c %c",&a,&b);
prinf("thanks, now some more");
fgets(cstring,35,stdin);

}

Problem is that whenever I enter the first vars from scanf, it skips to the end of the program. How do I do multiple inputs?

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
wesbos
  • 24,103
  • 27
  • 99
  • 139

4 Answers4

8

The first problem is that the scanf() reads two characters, but not the newline afterwards.

That means your fgets() reads the newline and finishes.

You are lucky your program is not crashing. You tell fgets() that it is getting an array of 35 characters, but rather than passing an array, you pass the character (not the address of a character, even). That also tells us you are not including #include <stdio.h> (you can't use scanf() reliably according to the C standard without a prototype for scanf() in scope), and you are not compiling with enough warnings enabled, or not paying enough attention to what your compiler is telling you.

You should be getting compiler warnings. For example, GCC 4.6.0 says:

/usr/bin/gcc -g -I/Users/jleffler/inc -std=c99 -Wall -Wextra -Wmissing-prototypes \
     -Wstrict-prototypes -Wold-style-definition xxx.c
xxx.c: In function ‘main’:
xxx.c:7: warning: implicit declaration of function ‘prinf’
xxx.c:8: warning: passing argument 1 of ‘fgets’ makes pointer from integer without a cast

And, darn it, I hadn't even noticed the spelling mistake of prinf() for printf() until I tried linking and the compiler rubbed my nose in it by saying "Don't know what prinf() is!".

If your compiler doesn't at least give the second warning, get yourself a better compiler.


Comment:

How do I stop it from reading the newline after it?

The problem is not stopping the scanf() from reading the newline; the problem is actually how to make it read it so that fgets() gets a clear run at the next line of input. It actually is modestly tricky - one reason why I seldom use scanf() (but I often use sscanf()). This does the job for simple inputs:

#include <stdio.h>
int main(void)
{
    char a,b,cstring[35];

    printf("please enter something");
    scanf("%c %c%*c", &a, &b);
    printf("thanks, now some more");
    fgets(cstring, 35, stdin);
    printf("OK: I got %c and %c and <<%s>>\n", a, b, cstring);
    return 0;
}

The %*c reads an extra character (a newline) without assigning it anywhere (that's because of the *). However, if there are multiple characters after the second non-blank, it is no help. I'd probably write a loop to read to the newline:

#include <stdio.h>
int main(void)
{
    char a,b,cstring[35];
    int c;

    printf("please enter something");
    scanf("%c %c", &a, &b);
    while ((c = getchar()) != EOF && c != '\n')
        ;
    printf("thanks, now some more");
    fgets(cstring, 35, stdin);
    printf("OK: I got %c and %c and <<%s>>\n", a, b, cstring);
    return 0;
}

Note that getchar() returns an int and not a char. This reliably discards everything on the first line of input. It also shows how to echo what you read - an important part of debugging.

Jonathan Leffler
  • 666,971
  • 126
  • 813
  • 1,185
  • sorry I am compiling with stdio. How do I stop it from reading the newline after it? – wesbos Apr 05 '11 at 03:42
  • ohhh I understand. Thanks so much for taking the time to explain that. – wesbos Apr 05 '11 at 04:00
  • @Wes: note that my code does not check that `scanf()` successfully read two characters; it should. It should also check that `fgets()` got input too. However, that would marginally clutter the answer, making it slightly harder for you to see the wood for the trees. – Jonathan Leffler Apr 05 '11 at 04:07
1

That's undefined behaviour. Your cstring variable, despite its name, is a single character, and you are attempting to read up to 35 characters into what its current value points to. In other words, the current character in cstring will be converted into a pointer and it will try to write your input there. That's going to be a memory location (most likely) between 0 and 255 inclusive.

That's what's causing your segmentation violation. Start with something like this instead:

#include <stdio.h>
int main(void) {
    char a,b,cstring[99];

    printf("please enter something");
    scanf("%c %c",&a,&b);
    printf("thanks, now some more");
    fgets(cstring,35,stdin);

    return 0;
}

Or, possibly better:

#include <stdio.h>
int main(void) {
    char a,b,cstring[99];

    printf("please enter something");
    fgets(cstring,35,stdin);
    sscanf(cstring,"%c %c",&a,&b);
    printf("thanks, now some more");
    fgets(cstring,35,stdin);

    return 0;
}

Or, if you want a more robust solution for user input, see here. It's a tried and tested method with very good error checking.

Community
  • 1
  • 1
paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
0

The problem is when the flow reaches fgets(), this API first looks at stdin for input and it finds a stray '\n' there. As for fgets() which said that this API returns when it encounters EOF or '\n', since fgets() got '\n' from stdin so it executed without waiting for user to enter something as the APIs returning conditions met.

Solution to the problem is that you use getchar(); after scanf and ignore the extra characters left by scanf(). e.g:

scanf("%lf",&e);
getchar();
fgets(t,200,stdin);

or

other solution can be to use sscanf with fgets. e.g:

#include <stdio.h>
int main() {
int j;char t[200];
fgets(t,200,stdin);
sscanf(t,"%d",&j);
}
Prashant Shubham
  • 348
  • 4
  • 18
-1

You could just use fflush(stdin) after using scanf which clears the issue

  • `fflush` is an output operation (it writes buffered data to the underlying stream). Using it on an input handle such as `stdin` has undefined behavior. – melpomene Jul 02 '18 at 01:31
  • See [Using `fflush(stdin)`](https://stackoverflow.com/questions/2979209/using-fflushstdin) for a nuanced discussion of the merits and otherwise of using `fflush(stdin)`. – Jonathan Leffler Dec 08 '19 at 10:34