Что означает `scanf(%*[^\n]%*c)`?

Я хочу сделать цикл на C, который, когда программа запрашивает целое число, а пользователь вводит нецифровой символ, программа снова запрашивает целое число.

Я только что нашел код ниже. но я не понимаю, что это значит scanf("%*[^\n]%*c"). Что означает ^\n? Что означает * перед ^\n и c?

/*

 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;
}

person Gustavo Alejandro Castellanos    schedule 06.05.2015    source источник


Ответы (5)


Разбивка scanf("%*[^\n]%*c"):

  • %*[^\n] сканирует все до \n, но не сканирует в \n. Звездочка (*) говорит ему отбросить все, что было отсканировано.
  • %*c сканирует один символ, который в данном случае будет \n, оставшимся после %*[^\n]. Звездочка указывает scanf отказаться от отсканированного символа.

И %[, и %c являются спецификаторами формата. Вы можете увидеть, что они делают здесь. Звездочки в обоих спецификаторах сообщают scanf, что данные, прочитанные этими спецификаторами формата, не сохраняются.

Как прокомментировал @chux, он очистит одна строка stdin (стандартный поток ввода) до символа новой строки включительно. В вашем случае строка с недопустимым вводом очищается из файла stdin.


Лучше использовать

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

чтобы очистить stdin. Это связано с тем, что в первом случае (одиночный scanf) %*[^\n] завершится ошибкой, когда первым сканируемым символом будет \n, а остальная часть строки формата scanf будет пропущена, что означает, что %*c не будет работать и, следовательно, , \n из ввода все равно будет во входном потоке. В этом случае этого не произойдет, так как даже если первый scanf завершится ошибкой, второй будет выполняться, так как это отдельные операторы scanf.

person Spikatrix    schedule 06.05.2015
comment
Деталь: Это, безусловно, не очищает stdin, когда несколько строк ввода находятся в stdin, но будет потреблять ввод до следующего конца строки включительно. Обычно достаточно для базовых приложений. - person chux - Reinstate Monica; 31.12.2018

Вы можете взять строку в качестве входных данных в C, используя scanf(“%s”, s). Но он принимает строку только до тех пор, пока не найдет первый пробел.

Чтобы взять строку в качестве входных данных, вы можете использовать scanf("%[^\n]%*c", s);, где определяется как char s[MAX_LEN], где MAX_LEN — максимальный размер s. Здесь [] — это символ набора сканов.

  1. ^\n означает ввод данных до тех пор, пока не встретится новая строка.

  2. Затем с этим %*c он считывает символ новой строки, и здесь использованный * указывает, что этот символ новой строки отбрасывается.

Также обратите внимание, что: после ввода символа и строки ввод предложения с помощью вышеупомянутого оператора не будет работать. Это связано с тем, что в конце каждой строки присутствует символ новой строки \n. Таким образом, оператор: scanf("%[^\n]%*c", s); не будет работать, потому что последний оператор будет читать символ новой строки из предыдущей строки. Это можно обработать различными способами, и один из них: scanf("\n"); перед последним оператором.

person Tanishka Singhal    schedule 12.07.2019
comment
ответ представляет собой дословное описание в hacker earth на один из вопросов - person Mohammad Yasir K P; 22.02.2021

Вы можете взять строку в качестве входных данных в C, используя scanf(“%s”, s). Но он принимает строку только до тех пор, пока не найдет первый пробел.

Чтобы взять строку в качестве входных данных, вы можете использовать scanf("%[^\n]%*c", s);, где s определяется как char s[MAX_LEN], где MAX_LEN — максимальный размер s. Здесь [] — это символ набора сканов. ^\n означает ввод данных до тех пор, пока не встретится новая строка. Затем с этим %*c он считывает символ новой строки, и здесь использованный * указывает, что этот символ новой строки отбрасывается.

person Gagan Agarwal    schedule 15.07.2018
comment
Если строка ввода состоит только из "\n", scanf("%[^\n]%*c", s); ничего не читает и оставляет "\n" в stdin. Не рекомендуется использовать этот код для чтения строки по этой причине и по той причине, что она не имеет ограничения по ширине, - person chux - Reinstate Monica; 31.12.2018

Предположим, char sen[max_length], где максимальная длина — это максимальный размер sen[].

этот scanf("%[^\n]%*c",&sen[]); поможет вам получить предложение целиком, пока не встретится следующая строка "\n" или нажата клавиша ввода, что делается с помощью "%[^\n]" здесь [ ] — символ набора сканирования. "%*c" будет читать символ новой строки, звездочка " * " используется для обозначения того, что символ следующей строки отбрасывается.

person Debanshu Datta    schedule 20.05.2019

%[^\n]%*c

Который будет читать все до новой строки в строку, которую вы передаете, а затем будет потреблять один символ (новую строку), не назначая его чему-либо (это «*» - это «подавление присваивания»).

В противном случае новая строка остается во входном потоке, ожидая немедленного завершения последующих директив формата %[^\n].

Проблема с добавлением символа пробела в директиву формата (%[^\n]) заключается в том, что пробел будет соответствовать любому пробелу. Таким образом, он съест новую строку с конца предыдущего ввода, но также съест любые другие пробелы (включая несколько новых строк).

person Pranit Patil    schedule 01.07.2019