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

int main(){
    int n=1,i,cont;
    char string[50];

    scanf("%d",&n);
    while(n!=0){
        gets(string);
        cont=0;
        for(i=0;i<strlen(string);i++){
            if(string[i]=='.'){
                cont++;
            }
        }
        if(cont%2==0){
            printf("S\n");
        }else{
            printf("N\n");
        }
        scanf("%d",&n);
    }
    return 0;
}

My problem is quite simple but troublesome, I want to read an integer value n, and then read a string, after that read n again, but whenever I run the program, it only reads the string value... but if I digit 0 the program ends... it's like my scanf is within the gets function.

melpomene
  • 84,125
  • 8
  • 85
  • 148
Lucas Ju
  • 5
  • 5

3 Answers3

2

Mixing scanf with gets or fgets is troublesome because they each handle newlines differently.

Get rid of the gets call (which is unsafe anyway) and replace it with the following scanf call:

scanf("%49s", string);

This will read at most 49 characters into string (i.e. one less that its size).

dbush
  • 205,898
  • 23
  • 218
  • 273
  • it works but i was trying to use gets to be able to put space between characters – Lucas Ju Apr 30 '17 at 01:05
  • 2
    @LucasJu: *Never* use `gets` - not only is it unsafe, it was removed from the standard library in the 2011 version of the standard. Note that `%d`, `%s`, etc., will skip over any leading whitespace. – John Bode Apr 30 '17 at 01:17
  • 1
    fgets() is much better than scanf() when entering a string. When the input of a string exceeds more than number of characters allowed, fgets() simply ignores the extra characters. So fgets() automatically prevents buffer overflow and you don't have to worry about the nuisance syntax of scanf("%s49s", string); If the size of string changes, there is no need to worry about modifying the number inside scanf() statement. The syntax of fgets( string, sizeof(string), stdin); – Nguai al Apr 30 '17 at 01:27
0

From OP's comments, it sounds like the goal is to be able to read strings containing spaces. While there are ways to accomplish this using scanf(), it would be better to use fgets(), which is at the least less error-prone.

The fgets() function can be used to read input for the number into a buffer, and this buffer can then be processed by sscanf() to extract the number. Since fgets() keeps the newline character, it is not left behind to interfere with the next I/O operation.

But, when fgets() is used to get the string, since the newline is retained, it may be desirable to remove it. This can be accomplished in a number of ways, but here strcspn() is used to provide the index of the first \r or \n character encountered; a \0 character is then written to this location, removing the terminating newline from the string.

The code below illustrates these suggestions. Note that both buffer[] and string[] are generously allocated to accommodate reasonably large inputs. If a user enters a large number of characters (more than 999 in this case), the extra characters are left behind in the input stream for the next I/O function call. Also note that the main loop has been streamlined a bit; now there is a for(;;) loop that never terminates, broken out of when the user enters 0 for the number. And, there is a nested loop within the main loop that prompts the user to enter a number until a valid number is entered. Since the #include <stdlib.h> was unnecessary, it was removed. Better code would check the values returned from the calls to fgets() for possible errors.

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

int main(void)
{
    int n = 1, cont;
    char buffer[1000];
    char string[1000];

    for (;;) {

        /* Loop until user enters a number */
        do {
            printf("Please enter a number: ");
            fgets(buffer, sizeof buffer, stdin);
        } while (sscanf(buffer, "%d", &n) != 1);

        /* Break on 0 */
        if (n == 0) break;

        /* Get a string, and remove trailing newline */
        printf("Please enter a string\n");
        fgets(string, sizeof string, stdin);
        string[strcspn(string, "\r\n")] = '\0';

        cont = 0;
        for (size_t i = 0; i < strlen(string); i++) {
            if (string[i] == '.') {
                cont++;
            }
        }
        if (cont % 2 == 0){
            printf("S\n");
        } else {
            printf("N\n");
        }
    }

    return 0;
}
Community
  • 1
  • 1
ad absurdum
  • 19,498
  • 5
  • 37
  • 60
-3

When you enter 5 for an example, you hit a new line character afterwards. So you are entering 2 characters: 5 and a new line character. That new line character is causing your headache.

The new line character is also considered an input.

In order to ignore this new line char, simply add a new line that acts as a garbage collection:

 char garbage[50];

 scanf( "%d", &n);
 fgets(garbage, sizeof(garbage), stdin);
Nguai al
  • 958
  • 5
  • 15
  • This can not be ended by entering 0 after entering a string. – BLUEPIXY Apr 30 '17 at 01:29
  • This won't work; it is almost never correct to end a `scanf()` format string with a whitespace character. Input will block until `EOF` is signalled from the keyboard. – ad absurdum Apr 30 '17 at 01:31
  • @DavidBowling - The problem is an input of an integer in this case. For entering a string, fgets() is a way to go. – Nguai al Apr 30 '17 at 01:38
  • 1
    This won't work for entering an integer; it will block the input waiting for the whitespace match to fail, or `EOF`. Since a newline is whitespace, each time ENTER is pressed, the newline is matched and ignored, and `scanf()` will just wait for more input. Try it. – ad absurdum Apr 30 '17 at 01:41
  • 1
    @DavidBowling - I just ran it using scanf("%d\n",&n); It ran fine. Is there a specific test which you recommend? – Nguai al Apr 30 '17 at 01:44
  • 1
    This is a well-known difficulty with `scanf()`. This code blocks waiting for more input: `int n; printf("Enter a number: "); scanf("%d\n", &n); printf("You entered: %d\n", n);` (in `main()` with the appropriate `#include`). – ad absurdum Apr 30 '17 at 01:48
  • Here is [an answer](http://stackoverflow.com/a/43033218/6879826) I gave to a related question once. – ad absurdum Apr 30 '17 at 01:50
  • @DavidBowling - My old way of doing this is as follows: char garbage[50]; Insert a statement fgets(garbage, sizeof(garbage), stdin); after a scanf() statement. This worked great. I picked this scanf("%d\n", &n); method from a person. When I tested it, it seemed to work. But I didn't know there was these ill effects. What do you think about my old method? – Nguai al Apr 30 '17 at 02:15
  • 4
    I suppose that would work, so long as there aren't too many characters left in the input stream. The canonical way to do this portably, when you know that there is at least a `\n` left in the input stream, is to use `int c; while ((c = getchar()) != '\n' && c != EOF);` The `scanf()` function is tricky to use correctly. The trailing whitespace thing catches even more experienced programmers off-guard sometimes. Your comment elsewhere about preferring `fgets()` was spot on. – ad absurdum Apr 30 '17 at 02:22