简体   繁体   中英

What is the difference between scanf(“%s”, &str) and scanf(“%s\n”, &str)?

Input

There will be several lines in the input terminated with a line containing a single * . This last line should not be processed. Each of the lines will contain either Hajj or Umrah .

Output

For each line of the input, output either Hajj-e-Akbar or Hajj-e-Asghar in separate lines without quotations. For the exact format refer to the sample.

Here's my code for this problem.

#include <stdio.h>

int main()
{
    char str[100];
    int i = 1;

    while (scanf("%s", &str))
    {
        if (str[0] == '*')
            break;
        else if (str[0] == 'H')
            printf("Case %d: Hajj-e-Akbar\n", i);
        else
            printf("Case %d: Hajj-e-Asghar\n", i);
        i++;
    }
}

For the input

Hajj
Umrah
*

When I gave this input at a time, the program provides the expected output by printing

Hajj
Case 1: Hajj-e-Akbar
Umrah
Case 2: Hajj-e-Asghar
*

But after getting * as input, the program is waiting for an Enter . After hitting Enter , the program terminates. But I want my program to terminate, whenever it gets * as input, not by pressing Enter . Please help me here. But this is not my question. My question is for the same input-

Hajj
Umrah
*

When I take input by scanf("%s\n", &str) . The program does not print the output Case 1: Hajj-e-Akbar after the first input Hajj but it prints the output for first input after taking the second input Umrah . Then the program is waiting for an Enter for the input * . The output is like this

Hajj
Umrah
Case 1: Hajj-e-Akbar
*

Then I press Enter , it prints the output Case 2: Hajj-e-Asghar for the second input Umrah and then waits for another input. This the output looks like after pressing Enter .

Hajj
Umrah
Case 1: Hajj-e-Akbar
*
Case 2: Hajj-e-Asghar

I don't understand how \n is making a difference in scanf .

Thank you.

I'm sorry if I can't explain my question correctly. I am new to programming.

scanf reads formated input, so when you use %s\n”, &str the string will consumed and stored in str as will the newline character, which will be present in the buffer when you press enter, the string will be stored and the newline character will be discarded.

Note that the correct usage is “%s\n”, str , str is already a pointer you shouldn't use & .

When you use “%s”, &str the newline character will be left in the buffer and will be consumed in the next loop, so str will be stored in the first iteration, and "\n" will be stored in str in the next iteration, only then you will be asked for input again, in the third iteration.

For completion, as stated in the comments bellow, as per the definition of scanf :

...any single whitespace character in the format string consumes all available consecutive whitespace characters from the input (determined as if by calling isspace in a loop). Note that there is no difference between "\n", " ", "\t\t", or other whitespace in the format string.

I would also advise you to limit the size of the string expected by scanf to avoid container overflow, something like %99s for a 100 charaters container like you have, and also check scanf return, in this case, it must be = 1 for each cycle.

To do what you want, which I gather is to get a character from stdin without pressing return you will need a SO specific method, here is a small example for Windows using <conio.h> library, and getch() :

#include <stdio.h>
#include <conio.h>

int main()
{
    int i = 1, c;

    while (1)
    {
        if ((c = getch()) == '*')
            return 0;
        else if (c == 'H')
            printf("Case %d: Hajj-e-Akbar\n", i);
        else
            printf("Case %d: Hajj-e-Asghar\n", i);
        i++;
    }
}

For Linux one option is to use also getch() from <ncurses.h> library, which you might need to install .

PS: Don't worry, your question is well built, specially being only the second in the site.

The trailing \n in the scanf is a bad idea: any whitespace character in the format string causes any sequence of whitespace characters to be discarded from the input stream. If reading from a file, you will not necessary have a problem but if you read from the terminal, scanf() will not return until you have typed the next item, and this will create major confusion as you experience, because the program's output will correspond to the previous item, not the one that was just typed... Never add trailing spaces or newlines in a scanf() format string.

You should test if scanf() returns 1 to avoid an infinite loop when it returns EOF at the end of file.

Note also that it is incorrect to pass &str : str is an array, passing it as str will effectively pass a pointer to its first element, which is correct.

Furthermore, you should tell scanf() the maximum number of characters that can be stored into the destination array to avoid undefined behavior on overlong input. Since the array is defined with a size of 100 , the format string should be "%99s" to leave space for the null terminator.

Finally, you need to hit Enter after the final * for 3 combined reasons, each of which would force this behavior:

  • the terminal device driver is line buffered by default, so the input is not made available to the program until you type Enter .
  • the standard input stream ( stdin ) is line buffered by default, so it will read data from the system handle until it gets a newline, and only then does scanf() get a chance to see the first character of the entered line.
  • scanf("%s", str) will keep its input stream until it gets the end of the word, a whitespace character or the end of file, so it does not return when you type just * .

Here is a modified version:

#include <stdio.h>

int main() {
    char str[100];
    int i = 1;

    while (scanf("%99s", str) == 1 && str[0] != '*') {
        if (str[0] == 'H') {
            printf("Case %d: Hajj-e-Akbar\n", i);
        } else {
            printf("Case %d: Hajj-e-Asghar\n", i);
        }
        i++;
    }
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM