2013-03-11 3 views
3

Я пытаюсь выяснить, как именно работает scanf. Если я код что-то вроде этого:Понимание Scanf - обработка форматированного ввода

scanf("%s %d %f", name, &age, &wage); 

введите в качестве стандартного ввода:

james 20 34000.25 

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

scanf("%s/%d/%f", name, &age, &wage); 

и я вхожу в качестве стандартного ввода:

james/20/34000.25 

я получаю строку james/20/34000.25 для значения строки и 0 и 0.00000 соответственно для целой и плавающей точкой значения. Я думал, что scanf будет обрабатывать косые черты так же, как обрабатывать пробелы в первой версии. Как я могу получить это, если пользователь вводит значение, разделенное косой чертой, я могу соответствующим образом присваивать значения переменным?

+1

В каждом ответе, который я когда-либо видел о scanf, есть что-то * решающее * отсутствует.Как вы узнаете, были ли успешно сопоставлены спецификации формата '% s','% d', '% f','% [^ /] или '% [^ /]? Что произойдет, если пользователь просто нажмет CTRL + Z в Windows или CTRL + d в Linux, чтобы закрыть stdin? scanf * возвращает *, и ваша программа счастлива использовать значения мусора? Что сканирует f * return *? * Scanf должен это сделать! Почему это так, вместо этого? * Потому что это [руководство] (http://pubs.opengroup.org/onlinepubs/009695399/functions/scanf.html). У вас * вы * прочитали руководство? – Sebivor

+0

... и в некоторых случаях возвращаемое значение не игнорируется; Он сравнивается с -1 для проверки ошибок файлов, но не против какого-либо * положительного * числа для проверки ошибок преобразования! -sigh- Зачем задавать вопросы, прежде чем пытаться прочитать руководство? Руководство отвечает на ваши вопросы, прежде чем они станут проблемами; У каждой проблемы, которую вы проводите в течение часа, есть руководство, которое вы могли бы прочитать, чтобы решить еще пятьдесят проблем (в дополнение к этому). Не говоря уже о том, чтобы перетащить в него другие человеческие часы ... Почему были написаны руководства, если их не читали те, кто узнал о соответствующих функциях? – Sebivor

+0

Это очень трудно узнать из руководства, когда вы не сталкиваетесь с реальной проблемой. Я читаю больше, чем большинство программистов, но я все еще редко чувствую, что знаю кое-что, пока мне не пришлось отлаживать его и бороться с ним лично. Кроме того, руководство C не является образцом ясности, и это помогает реальным людям указать, что конкретно неправильно с MY кодом. Тем не менее, спасибо за информацию! – user1427661

ответ

4

%s матчи без пробельных символов (и это жадный матч: он не собирается возвращаться назад, чтобы увидеть, если какой-либо другой матч возможен) Для того, чтобы соответствовать без символов прямого слэша, используйте %[^/]

(Заметим также, что символ пробела (совпадение нуля или более пробельных символов) в строке Scanf имеет очень различное поведение от не-пространства не-процентного характера, такие, как '/' (точно соответствовать '/')

2

Чтобы соответствовать как пространственно-отделили и входы, разделенные косой чертой, вам потребуется небольшая сложная строка формата:

if (scanf("%[^ /]%*1[ /]%d%*1[ /]%f", name, &age, &wage) == 3) 
    ...data was read properly... 
else 
    ...something went wrong... 

Первая спецификация преобразования - это набор сканирования, который принимает последовательность незабитых, без косых червей (поэтому он останавливается при первом пробеле или косой чертой). Было бы лучше указать верхнюю границу того, сколько символов будет принято, чтобы избежать stack overflow; например, если char name[32];, затем %31[^ /] (обратите внимание, что вы выберете один за другим). Вторая спецификация преобразования %*1[ /] принимает один символ (1), который является либо пустой, либо косой чертой [ /], и не присваивает ее какой-либо переменной (*). Третья спецификация преобразования - это стандартный числовой ввод, пропускание ведущих заготовок, позволяющих вводить отрицательные числа и т. Д. Четвертая спецификация преобразования такая же, как и вторая, а пятая - стандартный формат для float (что означает, что 34000.25 с 7 значащими цифрами находится на внешнем конце диапазона представляемых значений).

Обратите внимание, что часть «что-то пошла не так» имеет трудное время, сообщающее об ошибке когерентно для пользователя. Вот почему многие люди, включая меня, рекомендуют не использовать scanf() или fscanf() и предпочитают использовать fgets() или, возможно, POSIX getline, чтобы прочитать строку от пользователя, а затем используйте sscanf() для ее анализа. Вы можете сообщить о проблемах гораздо легче. Также обратите внимание, что возвращаемое значение от scanf() - это количество успешных заданий; он не учитывает спецификации преобразования, которые включают *.

Смежные вопросы