scanf: "% [^ \ n]" пропускает второй вход, но "% [^ \ n]" нет. Зачем? - PullRequest
27 голосов
/ 21 мая 2011

Рассмотрим следующий код:

#include <stdio.h>

int main (void)
{
  char str1[128], str2[128], str3[128];

  printf ("\nEnter str1: ");
  scanf ("%[^\n]", str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf ("%[^\n]", str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf ("%[^\n]", str3);
  printf ("\nstr3 = %s", str3);

  printf ("\n");
  return 0;
}

Когда он выполняется, только первые scanf останавливаются для приглашения.Программа не останавливается в течение следующих scanf с.Но если строка формата изменяется с "%[^\n]" на " %[^\n]" (обратите внимание на пробел перед %), то все работает нормально.Принимается ли какой-либо существующий символ новой строки из предыдущего входного буфера автоматически?Но очистка stdin не решает эту проблему.

В чем причина этого.

Ответы [ 6 ]

40 голосов
/ 21 мая 2011

Вам просто нужно «потреблять» символ '\n' после того, как вы прочитали, что вы хотите.Используйте следующую директиву формата:

"%[^\n]%*c"

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

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

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

Обновление вашего примера:

  char* fmt = "%[^\n]%*c";

  printf ("\nEnter str1: ");
  scanf (fmt, str1);
  printf ("\nstr1 = %s", str1);

  printf ("\nEnter str2: ");
  scanf (fmt, str2);
  printf ("\nstr2 = %s", str2);

  printf ("\nEnter str3: ");
  scanf (fmt, str3);
  printf ("\nstr2 = %s", str3);

  printf ("\n");
7 голосов
/ 21 мая 2011

Когда вы используете scanf() для чтения строк, ваша строка формата (%[^\n]) говорит функции читать каждый символ, который не '\n'. Это оставляет символ '\n' во входном буфере. Поэтому, когда вы пытаетесь прочитать str2 и str3, scanf() каждый раз находит в буфере первое значение '\n' и из-за строки формата не удаляет его из входного буфера. То, что вам нужно, это getchar() между моментами, которые вы читаете из входного буфера (часто помещается сразу после scanf()). Поскольку в буфере уже есть '\n', ваша программа не будет зависать, потому что ей не придется ждать ввода для получения getchar(). Попытайся. :)

Для тех, кто не знает, что делает этот модификатор scanf(), вот соответствующий отрывок из http://linux.die.net/man/3/scanf -

[* * тысяча двадцать-один

Соответствует непустой последовательности символы из указанного набора принятые персонажи; следующий указатель должен быть указатель на символ, и там должно быть достаточно места для всех символы в строке плюс завершающий нулевой байт. Обычный скип ведущих пробелов подавляется. Строка должна состоять из символы в (или не в) конкретном задавать; набор определяется символы между открытой скобкой [ символ и закрывающая скобка] персонаж. Набор исключает те символы, если первый символ после того, как открытая скобка является круговым (^). Включить закрывающую скобку в установить, сделать его первым символом после открытый кронштейн или круговая скоба; любая другая позиция завершит сет. Символ дефиса - это тоже специальный; когда находится между двумя другими персонажи, добавляет все промежуточные символы для набора. Чтобы включить дефис, сделай его последним символом перед финальной закрывающей скобкой. За Например, [^] 0-9-] означает набор "все, кроме закрывающей скобки, ноль через девять и дефис ". Струна заканчивается появлением символ не в (или, с круговой, в) установлен или когда поле ширина заканчивается.

3 голосов
/ 06 января 2014

ТАКЖЕ: Чтобы прочитать строку:

scanf("%[^\n]\n", a);

// это означает чтение до тех пор, пока вы не встретите '\ n', а затем выбросить '\ n'

:)

1 голос
/ 04 декабря 2017

Просто используйте getchar () после функции scanf ().

0 голосов
/ 13 ноября 2017

Просто добавив немного к ответу выше - Если мы хотим удалить какой-то конкретный шаблон, предположим, числа 0-9, из входного потока, то мы должны будем использовать getchar () для очистки буфера.

scanf("%[^0-9\n]", str1);
while(getchar() != '\n'); // this approach is much better bcz it will
                         // remove any number of left characters in buffer.
scanf("%c", &ch);

Так что здесь, если вы передадите ashish019, то на str будет скопирован только ashish, а 019 останется в буфере, так что для очистки вам потребуется getchar () несколько раз.

0 голосов
/ 15 декабря 2012

используйте fflush(stdin) для очистки буфера ввода после чтения каждого ввода.

...