0

What is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?

int main() 
{
    char ch;
    char str [100];
    char s[100];
    scanf("%c",&ch);
    printf("%c",ch);
    scanf("%s",&str);
    printf("\n%s",str);
    scanf("\n");            // <<< what is the purpose of this line
    scanf("%[^\n]%*c",s);
    printf("\n%s",s);
    return 0;
}

So what is the use of scanf("\n"); statement before scanf("%[^\n]%*c", s) ?

user3386109
  • 34,287
  • 7
  • 49
  • 68
  • 2
    Looks like it is trying to consume the expected newline character. But this is not a very good code. – Eugene Sh. Sep 19 '22 at 21:27
  • 1
    The same thing can be accomplished by putting a space at the beginning of the next scanf format. – Barmar Sep 19 '22 at 21:29
  • 1
    The `scanf` function is notoriously bad dealing with arbitrary user input, especially with newlines. The author should have opted for `fgets` and parse the line afterwards. – Cheatah Sep 19 '22 at 21:43
  • 1
    If you're trying to read lines (which is what `scanf("%[^\n]%*c", s)` is trying to do), then you should be using `fgets`. `scanf` isn't a line-oriented parser. – user3386109 Sep 19 '22 at 21:43

2 Answers2

4

What is the use of scanf("\n");

The true answer is probably that the original author of this code was flailing, desperately trying to get scanf to work, despite scanf's various foibles.

Other evidence that the original author was having problems:

scanf("%c", &ch);

When reading individual characters, the %c often does not work as expected or as desired. Most of the time, at least in code like this, it is necessary to add a space, like this: " %c".

scanf("%[^\n]%*c", s);

This line, also, is difficult to understand. It is attempting to read one full line of text, a task which scanf is not well-suited for.

Overall the code appears to be attempting to read one single character, followed by one string (not containing whitespace), followed by one full line of text (possibly containing whitespace).

Given its shortcomings (and scanf's shortcomings), I'd say it's not even worth trying to figure out what the original code will do. A considerably cleaner way of accomplishing this task (still using scanf) would be

if(scanf(" %c", &ch) != 1) exit(1);
printf("%c\n",ch);
if(scanf("%99s", str) != 1) exit(1);
printf("%s\n", str);
if(scanf(" %99[^\n]", s) != 1) exit(1);
printf("%s\n", s);

Note these changes:

  • checking return value of scanf
  • extra space in " %c", as mentioned
  • %99s instead of plain %s, to avoid array overflow
  • no & before str with %s
  • extra space with %[…] also
  • length modifier 99 with %[…] also
  • no %*c after %[…]
  • (cosmetic/stylistic) printing \n at the end of each line

If you're trying to do anything at all fancy, it's often much easier to just skip scanf, and go with more powerful techniques. I might use something like this:

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

int main() 
{
    char chbuf[5];
    char ch;
    char str [100];
    char s[100];

    printf("enter a character:\n");
    if(fgets(chbuf, 5, stdin) == NULL) exit(1);
    ch = *chbuf;
    printf("%c\n", ch);

    printf("enter a string:\n");
    if(fgets(str, 100, stdin) == NULL) exit(1);
    str[strcspn(str, "\n")] = 0;  /* strip \n */
    printf("%s\n", str);

    printf("enter a line:\n");
    if(fgets(s, 100, stdin) == NULL) exit(1);
    s[strcspn(s, "\n")] = 0;
    printf("%s\n", s);
}

This simply used fgets to read all input, one line at a time. To fetch a single character, it then grabs the first character of a short line. (Also it's printing explicit prompts, since that helps to avoid confusion.)

One small drawback of fgets is that it always leaves the \n in the buffer. I've used a common albeit somewhat obscure trick to strip it back off; see this question for an explanation.

This modified program works, although it is different from the original in one significant respect: it will allow whitespace in the first string read as well as the second.

Also, the modified program insists that the three inputs be on three separate lines, while the original would have accepted them all on the same line (or on two lines, or on three lines). Whether that is an improvement or a disimprovement, I can't say. :-)

If you want to limit yourself to a subset of scanf's full complexity, using simple invocations of it for the simple uses it's well-suited for, and avoiding it for the more complicated problems that it's dreadfully painful to use for, you might read the suggestions at this answer.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
2

After this incorrect call of scanf

scanf("%s",&str);

where the second parameter shall be

scanf("%s",str);

the input buffer can contain the new line character '\n' and the next call of scanf

scanf("%[^\n]%*c",s);

can read as a result an empty string.

So this call

scanf("\n");

is an attempt to remove the new line character from the input buffer.

However it will be better just to write

scanf(" %[^\n]%*c",s);

See the leading space in the format string. It allows to skip white space characters in the input buffer.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    Not completely right, in that `scanf` cannot read an empty string to match a `%[` (or `%s`) directive. It will have a matching failure instead. The difference is visible in the effect on the destination object, in the return value, and (possibly) in whether any attempt is made to match subsequent directives. – John Bollinger Sep 20 '22 at 00:34