Что указывает строка формата "% * [^ \ n]" в операторе scanf ()? Как подавитель присваивания (*) и отрицательный набор сканирования ([^) работают вместе? - PullRequest
5 голосов
/ 28 октября 2019

Я знаю о введении набора сканирования со спецификатором преобразования [, который в последующем указывает символы для совпадения или несоответствия с дополнительной вставкой символа ^.

Для этого в ISO/ IEC 9899/1999 (C99) гласит:

Символы в скобках (список сканирования) составляют набор сканирования, если только символ после левой скобки не является окружностью (^), в этом случаенабор сканирования содержит все символы, которые не отображаются в списке сканирования между обхватом и правой скобкой.

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

Далее идет оператор присваивания-подавления *:

Для этого в ИСО / МЭК 9899/1999 (C99) указано:

Если подавление присвоения не было указано *, результат преобразования помещается вобъект, на который указывает первый аргумент после аргумента формата, который еще не получил результат преобразования.

В случае fe scanf("%*100s",a); это означает, что последовательность из 100 символов взята из stdin если только символ пробела не найден, но не назначен на a, если a является правильно определенным char массивом из 101 элемента (char a[101];).


Но чтотеперь достигается строка формата "%*[^\n]" в выражении scanf () -? \n остается в stdin?

Как работают супрессор назначения * и отрицательный набор сканирования [^ вместе?

Означает ли это, что:

  1. При использовании * всех символовсоответствующие этому формату строки берутся из stdin, но точно не назначены?, а
  2. \n не берутся из stdin, но используются для определения операции сканирования для соответствующегострока формата?

Я знаю, что каждый из этих [^ и * делает один, но не вместе. Вопрос в том, каков результат сочетания этих двух элементов, объединенного с отрицательным набором сканирования \n.


. Я знаю, что существует аналогичный вопрос о переполнении стека, который охватывает понимание%[^\n] только здесь: Что означает% [^ \ n] в строке формата scanf () . Но ответы там не помогают мне с моей проблемой.

Ответы [ 4 ]

5 голосов
/ 28 октября 2019

%[^\n] читает до, но не включает следующий \n символ. На простом английском языке он читает строку текста. Обычно строка хранится в строковой переменной char *.

char line[SIZE];
scanf("%[^\n]", line);

Модификатор * подавляет такое поведение. После прочтения строка просто отбрасывается, и переменная не требуется.

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

* не изменяет способ обработки ввода. В любом случае, все, кроме следующего \n, но не включая его, читается из стандартного ввода. При условии отсутствия ошибок ввода / вывода гарантируется, что при следующем чтении из stdin будет отображаться \n или EOF.

Какой оператор scanf() следует использовать, если я хочу прочитать ипосле этого отбрасывать каждый символ в stdin, включая символ \n?

Добавить %*c, чтобы также потреблять \n.

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

Почему вместо %*cвсего \n? Если бы вы использовали \n, он бы не потреблял только один символ новой строки, он занимал бы любое количество пробелов, табуляции и новых строк. \n соответствует любому количеству пробелов. Лучше использовать %*c, чтобы использовать ровно 1 символ.

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

См. Также:

Могу ли я использовать fflush() вместо этого?

Нет, не надо. fflush(stdin) не определено.

Не является ли отрицаемый набор сканирования [\n] полностью избыточным, поскольку scanf() завершает процесс сканирования соответствующей строки формата при первом появлениисимвол пробела по умолчанию?

С %s, да, он прекратит чтение с первого символа пробела. %s читает только одно слово. %[^\n], напротив, читает всю строку. Он не будет останавливаться на пробелах или табуляциях, только на новых строках.

В более общем смысле, в квадратных скобках актуальны только точные перечисленные символы. Для пробелов нет особого поведения. В отличие от %s он не пропускает начальные пробелы и не останавливает обработку рано, если встречает пробелы.

2 голосов
/ 28 октября 2019

Остается ли \n в stdin?

Да, это так.

Но что теперь делает строка формата "%*[^\n]" вscanf() -statement достижения?

Он читает все символы из входного потока, пока не достигнет новой строки, и отбрасывает их, не удаляя новую строку из входного потока.

При использовании * все символы, соответствующие этой строке формата, берутся из stdin, но не назначаются?

Правильно.

\n isnне взято из stdin, но используется для определения операции сканирования для соответствующей строки формата?

Точно. Когда достигается \n, большинство scanf s используют ungetc для перемещения символа обратно во входной поток.

Я знаю, что каждый из этих [^ и * делает по отдельности, но не вместе.

Помещение * перед [^ делает именно то, что делает только [^, за исключением того, что он не читает входные данные в аргумент и вместо этого отбрасывает их.

Если вы хотите отказаться от \n впоследствии, используйте эту строку формата:

"%*[^\n]%*c"
1 голос
/ 28 октября 2019
  • %[^\n] говорит scanf прочитать все до символа новой строки ('\n') и сохранить его в соответствующем аргументе.
  • %*[^\n] говорит scanf прочитать все досимвол новой строки ('\n') и сбросьте его вместо сохранения.

Примеры:

  • Ввод Hi there\n в scanf("%[^\n]", buffer); приводит к buffer содержимомуHi there и остаток stdin содержимого \n
  • Ввод Hi there\n в scanf("%*[^\n]"); приводит к Hi there сканированию и удалению из stdin и остатка stdin содержимого \n.

Обратите внимание, что оба %[^\n] и %*[^\n] завершатся ошибкой, если первый встреченный символ будет \n. После сбоя stdin остается нетронутым, а scanf возвращается, в результате чего остальная часть строки формата игнорируется.


Если вы хотите удалить строку stdin дои включая символ новой строки, используя scanf, используйте

scanf("%*[^\n]"); /* Read and discard everything until a newline character */
scanf("%*c");     /* Discard the newline character */
1 голос
/ 28 октября 2019

Так как он, кажется, не охвачен, рабочий способ прочитать все до новой строки, а затем новой строки, это:

scanf("%*[^\n]%*c");
  • %*[^\n] читает и сбрасывает до следующего символаis newline
  • %*c читает и отбрасывает только один символ, в соответствии с приведенным выше будет перевод новой строки

Вы также можете прочитать новую строку с %c в переменной и посмотреть, если выдействительно получить новую строку успешно, но вы также можете просто напрямую проверить EOF или ошибку и не беспокоиться об этом.

...