запутался в getchar и scanf

Я действительно запутался в использовании getchar() и scanf(). В чем разница между этими двумя?

Я знаю, что scanf() [и семья] получают посимвольно от пользователя [или файла] и сохраняют в переменную, но делает ли это сразу или после нажатия чего-либо (Enter)?

и я действительно не понимаю этот код, я видел много фрагментов кода, использующих getchar(), и все они позволяют вам печатать на экране все, что вы хотите, и никакого ответа не происходит, но когда вы нажимаете enter, он закрывается.

int j, ch;

printf("please enter a number : \n");

while (scanf("%i", &j) != 1) {
    while((ch = getchar()) != '\n') ;
    printf("enter an integer: ");
}

Здесь, в этом коде, я не могу использовать scanf(), чтобы получить символ за символом и проверить его? Кроме того, что означает эта строка?

scanf("%i", &j) != 1

потому что, когда я нажал 1, это не изменилось, когда я нажал 2? что делает эта штука?

а когда эта строчка будет?

printf("enter an integer: ");

потому что этого никогда не бывает.


person Salahuddin    schedule 07.01.2014    source источник


Ответы (6)


Что ж, scanf — это универсальная служебная функция, которая может считывать многие типы данных на основе строки формата, в то время как getchar() читает только один символ.

В принципе,

char someCharacter = getchar();

эквивалентно

char someCharacter;
scanf("%c", &someCharacter);

Я не уверен на 100%, но если вам нужно прочитать только один символ, getchar() может быть «дешевле», чем scanf(), так как накладные расходы на обработку строки формата не существуют (это может иметь значение, если вы читаете много символов). , как в огромном цикле for).

На второй вопрос.

Этот код:

scanf("%i", &j) != 1

означает, что вы хотите, чтобы scanf прочитал целое число в переменной 'j'. Если чтение выполнено успешно, то есть следующий ввод в потоке фактически является целым числом, scanf вернет 1, так как он правильно прочитал и присвоил 1 целое число.

См. самый старый ответ на этот вопрос SO для получения более подробной информации о возвращаемых значениях scanf.

person nestedloop    schedule 07.01.2014
comment
Если чтение выполнено успешно, то есть следующий ввод в потоке на самом деле является целым числом, scanf вернет 1, вот вопрос, я читал, что scanf() возвращает количество прочитанных символов, а не если он читает целое число, возвращает 1, Я попробовал, и действительно получилось так, что при вводе целого числа возвращалось 1, а при вводе строки символов возвращалось 0. Так как же он возвращает количество прочитанных символов? Я смущен - person Salahuddin; 07.01.2014
comment
@Salahuddin Возвращает количество успешно сопоставленных и назначенных элементов ввода, какими бы они ни были. Скажем, этот вызов получает правильный ввод: scanf(%i%c%s, &someInt, &someChar, &someString), он вернет 3. - person nestedloop; 07.01.2014
comment
@nestedloop getchar() возвращает int, а не char. Откуда нам знать иначе, когда встречается EOF. - person hetepeperfan; 07.01.2014
comment
@hetepeperfan Да, getchar () возвращает беззнаковый char, преобразованный в int, если только не происходит EOF. Но тогда я говорил о том, что возвращает scanf, а не getchar. - person nestedloop; 07.01.2014
comment
@nestedloop Я думаю, что примеры кода в ответе должны способствовать хорошему стилю и предотвращать ошибки. На мой взгляд, char c = getchar(); не способствует хорошему стилю. - person hetepeperfan; 07.01.2014
comment
@Salahuddin Если вы делаете вызов, например, scanf(%i, &someInteger), это означает, что scanf ожидает получить целое число в качестве входных данных. Если вы введете нечисловую строку, она не получит ожидаемое целое число, поэтому значения 0 (ноль) будут правильно прочитаны и присвоены, поэтому будет возвращено 0 (ноль). - person nestedloop; 07.01.2014
comment
@hetepeperfan Отредактировано. Мы существуем только для того, чтобы служить (или угождать). - person nestedloop; 07.01.2014
comment
@nestedloop Я могу быть здесь, чтобы побеспокоить вас, теперь я понял, что первый цикл while не произойдет, пока я не введу строку (не число), хорошо, поэтому я ввел символ (например, c), затем нажал клавишу ввода, теперь мы находятся в цикле while, встречающемся со вторым циклом while, что означает (если вы не нажмете Enter, оставайтесь на месте и ничего не делайте), верно? так почему, когда я ничего не нажимал, появляется ввод целочисленной строки ?? Я думаю, что он не должен появляться, пока я не нажму Enter, чтобы выйти из второго цикла while, верно? Пожалуйста, объясните и будьте терпеливы .. спасибо - person Salahuddin; 07.01.2014
comment
@Salahuddin Я не могу точно знать, что вы ввели, но это действительно странно. Я постараюсь воспроизвести это и вернусь, если найду объяснение. Тем временем попробуйте еще раз внимательно. - person nestedloop; 07.01.2014
comment
@Salahuddin Разве вы не нажимали «ввод» после того, как написали строку? Потому что из вашего кода не нужно дважды нажимать Enter. Под этим я подразумеваю, что вы вводите какую-то строку блабла, а затем, если вы нажимаете ввод, это принимается во внимание, как вы это делаете с getchar. Попробуйте напечатать что-нибудь во втором цикле, например значение ch, посмотрите, когда оно выйдет из него. - person nestedloop; 07.01.2014
comment
@nestedloop да, я нажал Enter после печати строки, поэтому он вошел в первый цикл, начав выполнение второго цикла while, поэтому я думаю, что мне нужно снова нажать Enter, чтобы выйти из второго цикла while, верно? - person Salahuddin; 07.01.2014
comment
@Salahuddin Вы поместили printf во второй цикл, как я предлагал ранее? Дело в том... что он мог войти в первый цикл, когда вы ПЕРВЫМ нажали ввод (после целого числа), затем вы ввели строку и снова нажали ввод, тем самым выйдя из второго цикла. Первый ввод также считается и не является целым числом для scanf. Я думаю, что это ответ на эту новую проблему. - person nestedloop; 07.01.2014
comment
давайте продолжим это обсуждение в чате - person Salahuddin; 07.01.2014

Насколько я понимаю, функция getchar будет читать ваш ввод по одному символу за раз. scanf будет читать все типы данных и будет более полезен для определения группы данных. Однако, что касается строк, мой учитель рекомендует использовать gets вместо scanf. Это связано с тем, что scanf перестанет «получать» данные при первом вставленном пробеле, как в предложении...

person AnujaPL    schedule 07.01.2014

while (scanf("%i", &j) != 1) {
    while((ch = getchar()) != '\n') ;
    printf("enter an integer: ");
}

Вот как этот код разбивается.

  1. scanf() consumes individual characters from the input stream until it sees a character that does not match the %i conversion specifier1, and that non-matching character is left in the input stream;
  2. scanf() attempts to convert the input text into a value of the appropriate type; i.e., if you enter the string "1234\n", it will be converted to the integer value 1234, the converted value will be assigned to the variable j, and the '\n' will be left in the input stream;
  3. if there are no characters in the input string that match the conversion specifier (such as "abcd"), then no conversion is performed and nothing is assigned to j;
  4. scanf() returns the number of successful conversions and assignments.
  5. if the result of the scanf() call is not 1, then the user did not enter a valid integer string;
  6. since non-matching characters are left in the input stream, we need to remove them before we can try another scanf() call, so we use getchar() to consume characters until we see a newline, at which point we prompt the user to try again and perform the scanf() call again.

<ч> 1. Спецификатор преобразования %i пропускает все начальные пробелы и принимает необязательно целые константы со знаком в восьмеричном, десятичном или шестнадцатеричном форматах. Таким образом, он будет принимать строки вида [+|-]{0x[0-9a-fA-F]+ | 0[0-7]+ | [1-9][0-9]*}

person John Bode    schedule 07.01.2014

scanf может сканировать произвольно отформатированные данные и анализировать их как несколько типов (целые числа, числа с плавающей запятой, строки и т. д.). Функция getchar просто получает один символ и возвращает его.

Выражение

scanf("%i", &j) != 1

считывает (возможно, со знаком) целое число из стандартного ввода и сохраняет его в переменной j. Затем он сравнивает возвращаемое значение функции scanf (которая возвращает количество успешно отсканированных конверсий) и сравнивает его с 1. Это означает, что выражение будет "истинным", если scanf не прочитал целочисленное значение. Таким образом, цикл будет продолжаться до тех пор, пока scanf не сработает.

Вы можете проверить этот scanf справочник.

То, что printf не происходит, может быть связано либо с тем, что оно никогда не происходит (используйте отладчик, чтобы выяснить это), либо с тем, что оно просто казалось не происходит, но на самом деле происходит, потому что вывод нужно сбросить. Сброс вывода выполняется либо путем печати новой строки, либо с помощью функции fflush:

fflush(stdout);
person Some programmer dude    schedule 07.01.2014
comment
возвращаемое значение функции scanf (которая возвращает количество успешно отсканированных преобразований). На самом деле со мной этого не произошло, scanf() вернул 1, когда я ввел целые числа, и 0, когда я ввел строки - person Salahuddin; 07.01.2014
comment
@Salahuddin И вот как это должно работать. Когда вы ввели целое число, он успешно просканировал и преобразовал целое число, в которое вы его просили, поэтому он возвращает 1, потому что он просмотрел и преобразовал один элемент. Когда вы вводили строку, она не могла преобразовать ее в целое число, поэтому возвращала 0, так как сканировала и преобразовывала нулевые элементы. - person Some programmer dude; 07.01.2014
comment
Извините, но все, что я знаю, это то, что scanf() сканирует ввод и сохраняет его в каком-то месте, так что вы имеете в виду под преобразованием, и когда вы ввели целое число, оно успешно просканировало и преобразовало целое число, которое вы просили его , я не просил преобразовать его в целое число - person Salahuddin; 07.01.2014
comment
@Salahuddin scanf читает текст (последовательность символов) и преобразует его в зависимости от кода формата, который вы ему даете. В формате "%i" вы просите scanf прочитать текст и преобразовать его в целое число. - person Some programmer dude; 07.01.2014

Насколько я знаю, scanf будет читать пользовательский ввод до первого пробела, учитывая указанный формат ввода. getchar, однако, читает только один символ.

scanf вернет количество аргументов списка форматов, которые были успешно прочитаны, как описано здесь. Вы получите тот же результат при нажатии 1 или 2, потому что оба они успешно прочитаны спецификатором формата %i.

person Mauren    schedule 07.01.2014

getchar считывает по одному символу из ввода. где as scanf может читать больше в зависимости от типа данных, который вы укажете.

не рекомендуется использовать scanf(), попробуйте использовать fgets(), это намного эффективнее и безопаснее, чем scanf.

person KARTHIK BHAT    schedule 07.01.2014
comment
fgets() можно использовать только для чтения строк/строк. Так что для чтения чисел fgets() довольно бесполезен. Для чтения строк более эффективно использовать функцию scanf(). - person Joel Klinghed; 07.01.2014
comment
@JoelKlinghed, fgets определенно безопаснее, чем использовать scanf при чтении строк. Для других типов данных это бесполезно, иначе вам придется использовать sscanf впоследствии. - person Devolus; 07.01.2014
comment
scanf("%a") обычно лучше, чем fgets, но он такой же нестандартный, как и getline(), который я бы назвал лучшим. - person Joel Klinghed; 07.01.2014
comment
@Devolus, да, я перепутал gets() и fgets() и исправил свой комментарий до того, как увидел твой комментарий. - person Joel Klinghed; 07.01.2014
comment
@JoelKlinghed, LOL, вчера я совершил аналогичную ошибку, перепутав fgets с fscanf. :) - person Devolus; 07.01.2014