Почему звонки на scanf работают так?Это в стандарте? - PullRequest
2 голосов
/ 04 ноября 2010

Я заканчивал упражнения K & R 7.4 и 7.5 и наткнулся на досадную «особенность», в которую я не верю стандартным состояниям.

Согласно K & R, способ действия для спецификации преобразования "% c "

" Следующие входные символы (по умолчанию 1) размещаются в указанном месте. Нормальный пропуск по пробелам подавлен; для чтения следующего непробельного символа,использовать% 1s "

Мой вопрос заключается в том, должен ли этот оператор читаться следующим образом:

" Следующие входные символы (по умолчанию 1)помещаются в указанное место. THEN, при последовательных вызовах scanf, при которых снова используется% c , нормальный пропуск по пробелу подавляется; для чтения следующего непробельного символа используйте% 1s"

... потому что этот код:

void test1()
{
   char t1, t2;

   scanf("%c %c", &t1, &t2);
   printf("%d\n", t1);
   printf("%d\n", t2);

   //INPUT is: "b d" (without quotes)
}

приводит к t1 = 98 (b) и t2 = 100 (d).(Пробелы пропущены)

Однако этот код:

void test2()
{
   char t1, t2;

   scanf("%c", &t1);
   scanf("%c", &t2);
   printf("%d\n", t1);
   printf("%d\n", t2);

   //INPUT is: "b d" (without quotes)
}

приводит к t1 = 98 (b) и t2 = 32 ('').(Пробельные символы NOT пропущены)

Читая оригинальную цитату, я думаю, что любой разумный человек будет понимать, что во время того же вызова scanf (% c) пропуск пропуска пропускается.Однако, похоже, что это не так.

Кажется, что для того, чтобы вернуть исходную функциональность, нужно полностью очистить стандартный ввод.

Это должно сработатьпуть?Это было задокументировано?Потому что я осмотрелся и не увидел много информации об этом.

Для справки, я программирую на C99.

Ответы [ 6 ]

13 голосов
/ 04 ноября 2010

Это потому, что пробел в строке, переданной в scanf, означает пропуск пробела. Если вы удалите пробел и используете "%c%c" вместо "%c %c", первая программа будет вести себя точно так же, как и вторая.

Итак, ответ на ваш вопрос: нормальный пропуск всегда подавлен, это просто пространство, которое делает магию.

3 голосов
/ 04 ноября 2010

Страница руководства для scanf в Linux гласит:

c Соответствует последовательности символов, длина которой определяется максимальной шириной поля (по умолчанию 1); следующий указатель должен быть указателем на символ, и должно быть достаточно места для всех символов (завершающий нулевой байт не добавляется). Обычный пропуск ведущих пробелов подавляется. Чтобы сначала пропустить пробел, используйте явный пробел в формате.

Я считаю, что это устраняет неоднозначность: c само по себе не пропускает пробелы; у вас должен быть явный пробел в строке формата. Поэтому, если вы измените свой второй пример на:

scanf("%c", &t1);
scanf(" %c", &t1);

Второй вызов scanf пропустит пробел из-за явного пробела.

2 голосов
/ 04 ноября 2010

Нет -% c просто читает следующий символ ввода, независимо от того, что это такое. Контраст с% s, который пропускает любое количество начальных пробелов, затем считывает до указанного числа символов (останавливается на указанном числе или когда встречает символ пробела).

Однако в вашем первом фрагменте кода в строке формата между двумя преобразованиями% c есть пробел. Пробел в потоке форматирования означает, что он должен пропустить все последовательные пробелы перед попыткой следующего преобразования.

2 голосов
/ 04 ноября 2010

Пробел между "% c% c" означает пропуск пробела между первым и вторым символом, "% c" на первом месте означает чтение любого символа.

0 голосов
/ 04 ноября 2010

Стандарт (C9899: TC3) говорит, что для% c и некоторых других спецификаций пробелы не пропускаются (7.19.6.2.8).

0 голосов
/ 04 ноября 2010

со страницы руководства scanf

Директива является одной из следующих:

  • Последовательность символов пробела (пробел, табуляция, новая строка и т. Д .; см. Isspace (3)). Эта директива соответствует любому количеству пробелов, включая ни одного, во входных данных.

и т.д.. В первом случае у вас есть эта директива, но во втором нет.

...