What does `scanf("%*[^\n]%*c")` mean?
Asked Answered
C

6

21

I want to make a loop in C that, when the program asks for an integer and the user types a non-digit character, the program asks again for an integer.

I just found the below code. but I don't understand what this means scanf("%*[^\n]%*c"). What does ^\n mean? What does the * before ^\n and c mean?

/*

 This program calculate the mean score of an user 4 individual scores,
 and outputs the mean and a final grade
 Input: score1, score2,score2, score3
 Output: Mean, FinalGrade

*/
#include <stdio.h>
//#include <stdlib.h>

int main(void){
  int userScore = 0; //Stores the scores that the user inputs
  float meanValue = 0.0f; //Stores the user mean of all the notes
  char testChar = 'f'; //Used to avoid that the code crashes
  char grade = 'E'; //Stores the final 
  int i = 0; //Auxiliar used in the for statement

  printf("\nWelcome to the program \n Tell me if Im clever enough! \n Designed for humans \n\n\n");
  printf("Enter your 4 notes between 0 and 100 to calculate your course grade\n\n");

  // Asks the 4 notes. 
  for ( ; i<=3 ; i++ ){
    printf("Please, enter your score number %d: ", i+1);

    //If the note is not valid, ask for it again

    //This is tests if the user input is a valid integer.
    if ( ( scanf("%d%c", &userScore, &testChar)!=2 || testChar!='\n')){
      i-=1;
      scanf("%*[^\n]%*c");

    }else{ //Enter here if the user input is an integer
      if ( userScore>=0 && userScore<=100 ){
    //Add the value to the mean
    meanValue += userScore;
      }else{ //Enter here if the user input a non valid integer
    i-=1;
    //scanf("%*[^\n]%*c");
      }    
    }
  }

  //Calculates the mean value of the 4 scores
  meanValue = meanValue/4;

  // Select your final grade according to the final mean
  if (meanValue>= 90 && meanValue <=100){
    grade = 'A';
  } else if(meanValue>= 80 && meanValue <90){
    grade = 'B';
  } else if (meanValue>= 70 && meanValue <80){
    grade = 'C';
  } else if(meanValue>= 60 && meanValue <70){
    grade = 'D';
  }
  printf("Your final score is: %2.2f --> %c \n\n" , meanValue, grade);

  return 0;
}
Cyrene answered 6/5, 2015 at 0:50 Comment(0)
B
41

Breakdown of scanf("%*[^\n]%*c"):

  • %*[^\n] scans everything until a \n, but doesn't scan in the \n. The asterisk(*) tells it to discard whatever was scanned.
  • %*c scans a single character, which will be the \n left over by %*[^\n] in this case. The asterisk instructs scanf to discard the scanned character.

Both %[ and %c are format specifiers. You can see what they do here. The asterisks in both the specifiers tell scanf, not to store the data read by these format specifiers.

As @chux commented below, it will clear a single line of the stdin (Standard Input Stream) up to and including the newline character. In your case, the line with invalid input gets cleared from the stdin.


It is better to use

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

to clear the stdin. This is because, in the former case (single scanf), %*[^\n] will fail when the first character to be scanned is the \n character and the rest of the format string of the scanf will be skipped which means that the %*c will not function and thus, the \n from the input will still be in the input stream. In this case, this will not happen as even when the first scanf fails, the second one will execute as they are separate scanf statements.

Bowfin answered 6/5, 2015 at 7:59 Comment(1)
Detail: This does not certainly "clear the stdin" when multiple lines of input are in stdin, yet will consume input up to and including the next end-of-line. Usually good enough for basic applications.Verjuice
C
0

You can take a string as input in C using scanf(“%s”, s). But, it accepts string only until it finds the first space.

In order to take a line as input, you can use scanf("%[^\n]%*c", s); where s is defined as char s[MAX_LEN] where MAX_LEN is the maximum size of s. Here, [] is the scanset character. ^\n stands for taking input until a newline isn't encountered. Then, with this %*c, it reads the newline character and here, the used * indicates that this newline character is discarded.

Cappadocia answered 15/7, 2018 at 6:9 Comment(1)
If a line of input only consists of "\n", scanf("%[^\n]%*c", s); does not read anything and leaves "\n" in stdin. Recommend against this code to read a line for that reason and that there is has no width limit,Verjuice
O
0

Suppose char sen[max_length] where maximum length is maximum size of sen[].

this scanf(“%[^\n]%*c”,&sen[]); will help you to get a entire sentence until the next line isn’t encountered “\n” or enter is pressed which is done with the help of “%[^\n]” here [ ] is the scan set character . the ”%*c” will read the newline character , asterisk ” * ” is used to indicate that the next line character is discarded.

Otho answered 20/5, 2019 at 4:46 Comment(0)
W
0

%[^\n]%*c

Which will read everything up to the newline into the string you pass in, then will consume a single character (the newline) without assigning it to anything (that '*' is 'assignment suppression').

Otherwise,the newline is left in the input stream waiting to immediately terminate the the subsequent %[^\n] format directives.

The problem with adding a space character to the format directive (%[^\n]) is that the space will match any white space. So, it will eat the newline from the end of the previous input, but it will also eat any other whitespace (including multiple newlines).

Wanderjahr answered 1/7, 2019 at 18:8 Comment(0)
L
0

Essentially this is two reads using scanf. The first part "%[^\n]" means 'read everything that is not a newline' and this is assigned to the character buffer str.

The second part "%*c" means 'read the next character but don't save it anywhere'; this gets rid of the newline that we didn't read in the first part.

https://www.sololearn.com/Discuss/2249429/what-s-the-use-of-scanf-n-c-in-c-programming

Loyalty answered 10/9, 2021 at 8:57 Comment(0)
A
0

In order to take a line as input, you can use scanf("%[^\n]%*c", s); where is defined as char s[MAX_LEN] where is the maximum size of . Here, [] is the scanset character. ^\n stands for taking input until a newline isn't encountered. Then, with this %*c, it reads the newline character and here, the used * indicates that this newline character is discarded.

Alkane answered 12/8, 2022 at 7:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.