Форматированный ввод данных в Си — функция scanf
В то время как функция printf() осуществляет форматированный вывод данных, функция scanf() осуществляет их форматированный ввод. Это значит, что поступающие на ввод данные преобразуются соответственно указанному формату(ам) и записываются по адресу(ам) указанной(ых) переменной(ых):
scanf(строка_формата, адреса_переменных);
Причина, по которой в scanf() передаются адреса, а не значения переменных, очевидна. Функция scanf() должна изменять значения переменных тех функций, из которых вызывается. Единственный способ — это получить адреса областей памяти.
Спецификации, допустимые в строке формата, для scanf() почти идентичны тем, что были описаны для функции printf() .
Ввод чисел, символов и строк
Пример ввода-вывода целого и вещественного чисел, символа и строки:
int a; float b; char ch, str[30]; scanf("%d%f%c%s", &a, &b, &ch, str); printf("%d %.3f %c %s\n", a, b, ch, str);
45 34.3456y hello 45 34.346 y hello
Здесь при выполнении программы все данные были введены в одну строку. Разделителем между числами и строками является пробел, а также любой другой символ пустого пространства (например, ‘\n’). Однако при считывании символа, пробел учитывается как символ; чтобы этого не произошло, в примере букву записали сразу после числа. Данные можно было бы ввести, разделяя их переходом на новую строку (опять же при этом надо иметь ввиду, как считывается символ).
В строке формата функции scanf() между спецификациями вполне допустимо поставить пробелы: %d %f %c %s . Они никакой роли не сыграют. Понятно, что данные можно было получить и так:
scanf("%d", &a); scanf("%f", &b); scanf("%c", &ch); scanf("%s", str);
Обратите внимание, перед переменной str отсутствует знак амперсанда. В последующих уроках вы узнаете, что имя массива уже само по себе является ссылкой на массив (другими словами, str содержит адрес начала массива).
В функции scanf() в спецификации формата вещественных чисел не указывается точность представления числа. Запись типа %.3f или %.10lf приведет к невозможности получить вещественное число. Чтобы получить число типа double используют формат %lf , для long double ‒ %Lf .
Для целых чисел: длинное целое ‒ %ld , короткое целое ‒ %hd . Существуют спецификации для ввода восьмеричных и шестнадцатеричных чисел.
Функция scanf() возвращает количество удачно считанных данных; т.е. значение, возвращаемое функцией, можно проанализировать и таким образом узнать, корректно ли были введены данные. Например:
int a; double b; char ch, str[30]; ch = scanf("%d %lf %s", &a, &b, str); if (ch == 3) printf("%d %.3lf %s\n", a, b, str); else printf("Error input\n");
Обычные символы в строке формата
В строке формата scanf() допустимо использование обычных символов. В этом случае при вводе данных также должны вводиться и эти символы:
int a, b, c; scanf("%d + %d = %d", &a, &b, &c); printf("Your answer is %d\n", c); printf("The correct is %d\n", a+b);
В данном случае, когда программа выполняется, ввод должен выглядеть примерно так: 342+1024 = 1366. Знаки «+» и » lang»>% , но перед буквой формата звездочку * . В таком случае данные считываются, но никакой переменной не присваиваются. Это можно использовать, например, когда нет определенной уверенности в том, что поступит на ввод, с одной стороны, и нужды сохранять эти данные, с другой:
float arr[3]; int i; for(i = 0; i 3; i++) scanf("%*s %f", &arr[i]); printf("Sum: %.2f\n", arr[0]+arr[1]+arr[2]);
Здесь предполагается, что перед каждым числом будет вводиться строка, которую следует проигнорировать, например:
First: 23.356 Second: 17.285 Third: 32.457 Sum: 73.098
Использование «шаблонов»
Для функции scanf() есть пара спецификаций формата, отдаленно напоминающих шаблоны командной оболочки и др. Формат […] позволяет получить строку, содержащую любые символы, указанные в квадратных скобках. Как только на ввод поступает символ, не входящий в указанный набор, считывание данных прекращается. Формат [^…] , наоборот, помещает в строку символы, не входящие в указанный набор, до тех пор пока не встретит любой из указанных.
В примере ниже как только поступает не цифра, считывание ввода завершается. При этом если первый символ — не цифра, то в str вообще ничего не записывается:
char str[30]=""; scanf("%[0-9]", str); printf("%s\n", str);
А в этом случае строке будет присвоена последовательность символов до любого из указанных знаков препинания:
scanf("%[^;. ]", str); printf("%s\n", str);
one two three four five! one two three four five
Обратите внимание, что в примере выше в строку были записаны как символы пробелов, так и символ перехода на новую строку. Таким образом, если надо прочитать одну строку вместе с пробелами, можно использовать такой подход:
scanf("%[^'\n']", str);
Здесь в строку считываются все символы, кроме перехода на новую строку. Как только встречается этот символ ‒ ‘\n’ , запись данных в переменную прекращается.
Некоторые особенности и ограничения функции scanf
Как только поступают некорректные данные, функция scanf() завершает свою работу. В примере:
scanf("%d%f", &a, &b);
если переменной a попытаться присвоить символ или строку, что невозможно, то в переменную b потом уже не получится записать число. Можно предположить, что так будет надежнее:
scanf("%d", &a); scanf("%f", &b);
Вроде бы неудачное считывание a не должно оказывать никакого влияния на b , т.к. это уже иной вызов scanf() . Но не все так просто: при некорректном вводе данные остаются в буфере и пытаются «навязать» себя последующим вызовам scanf() . Поэтому при использовании scanf() надо думать о том, как в случае некорректного ввода очистить буфер. Например, это можно сделать так, как показано ниже, или путем использования специальных функций (здесь не рассматриваются):
// если данные не удалось присвоить, if (scanf("%d", &a) != 1) // то выбросить их в виде строки scanf("%*s"); scanf("%f", &b);
- На прошлом занятии вы написали программу, содержащую функции, вычисляющие факториал числа и заданный элемент ряда Фибоначчи. Измените эту программу таким образом, чтобы она запрашивала у пользователя, что он хочет вычислить: факториал или число Фибоначчи. Затем программа запрашивала бы у пользователя либо число для вычисления факториала, либо номер элемента ряда Фибоначчи.
- Напишите программу, которая запрашивает у пользователя две даты в формате дд.мм.гггг. Дни, месяцы и года следует присвоить целочисленным переменным. Программа должна выводить на экран информацию о том, какая дата более ранняя, а какая более поздняя.
- Используя цикл, напишите код, в котором пользователю предлагается вводить данные до тех пор, пока он не сделает это корректно, т.е. пока все указанные в scanf() переменные не получат свои значения. Протестируйте программу.
Курс с решением задач:
pdf-версия
Как ввести неопределённое количество строк С++?
Здравствуйте. Сразу оговорюсь, я только начала изучать строки, я не знаю векторов и много еще чего. Нужно ввести неопределенное количество строк. Проблема в том, что я не знаю как это осуществить. Моих знаний явно не хватает для этого. Пожалуйста, помогите.
- Вопрос задан более двух лет назад
- 1451 просмотр
3 комментария
Простой 3 комментария
А что сделать-то надо?
Karapolo @Karapolo Автор вопроса
cicatrix, ввести данные и работать с ними.
Karapolo, как осуществляется приём входных данных? С консоли, из файла, из базы данных, с интернет-ресурса?
Написать надо что? Отдельную функцию или программу целиком?
Есть ли ограничения, чем можно пользоваться, чем нельзя?
Потому как в простом случае, приём строки с консоли осуществляется вот так:
#include std::string str; std::getline(std::cin, str);
Но у того, кто дал тебе это задание, могут быть иные идеи в отношении использования string, например.
Решения вопроса 2
Алексей Уколов @alexey-m-ukolov
Такое условие означает, что вам нужно со строкой работать посимвольно, а не писать её всю в память, потому что памяти может не хватить.
Ответ написан более двух лет назад
Karapolo @Karapolo Автор вопроса
А что мне делать с пробелами, если я буду вводить посимвольно? Как это осуществить? Я пробовала через scanf(«%c», s), но у меня это не получилось. Или через массив? Но даже если так, то нам не известно количество символов, также есть еще пробелы.
Алексей Уколов @alexey-m-ukolov
Что «это»? Что «делать»? Массив — это не посимвольно.

Data Science
смотря на сколько привередливый проф. Может быть реально как сказал Алексей, но
обычно в универе такие ключевые слова как «неопределенное» означает что-то динамическое. Т.е. Вектор.
Для самых отбитых можно сделать функцию буфера, т.е. если ветор имеет более «х» строк, то выкачать это в фаил (но не думаю, что это потребуется).
А алгоритм в принципе простой, надо только перевести в код
Инициализируй переменную статуса меню
Задекларируй Вектор, куда будут попадать все данные
Инициализируй переменные для статистики (если их много, желательно сделай отдельный класс, а на этом месте будет обьект этого класса).
напиши while loop и используй сканнер, который добавляет строки в вектор до тех пор, пока к примеру пользователь не нажмет 0, где 0 будет считаться выходом из программы, т.е. break
тут выбор, или ты сразу после добавления строки делаешь статистику, или после того как пользовательно нажмет кнопку «0» и тогда для всего вектора.
Если же второе, то делаешь опять for loop на вектор и на каждую строку пишешь нужную обработку статистики.
Вывод данных: тут уж проблем с статистикой из класса быть не должно.
Проблему я вижу в другом, «я только начала изучать строки, я не знаю векторов и много еще чего»
Как ты это писать то собираешься? Готовься к малому сну )) А выучить это надо, я думаю с такими заданиями дальше у вас будет по нарастающей. Пропустишь это — потом опустишь вообще руки.
Конкретно с некоторыми позициями тут помогут спокойно. Писать же все. Для этого есть фриланс.
Как прочитать неопределенное количество строк с клавиатуры?
Мне необходимо ввести с клавиатуры определенной число строк, содержащих float числа. В первой строке вводится число — количество строк, в каждой последующей строке вводится два float числа. Мой вариант для 3 строк выглядит так:
N = int(input()) a1 = list(map(float, input().split())) a2 = list(map(float, input().split())) a3 = list(map(float, input().split())) b1 = a1[0], a2[0], a3[0] b2 = a1[1], a2[1], a3[1]
Но что делать если количество строк заранее не известно и может быть 5, 6 и т.д. Подскажите как будет выглядеть код, пожалуйста
Отслеживать
Timur Shleminov
задан 19 апр 2019 в 11:11
Timur Shleminov Timur Shleminov
47 4 4 бронзовых знака
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Используйте цикл, и сохраняйте данный в список списков:
n = int(input()) b = [] for i in range(n): a = list(map(float, input().split())) b.append(a) print(b)
Отслеживать
ответ дан 19 апр 2019 в 12:21
20.4k 4 4 золотых знака 25 25 серебряных знаков 52 52 бронзовых знака
-
Важное на Мете
Похожие
Подписаться на ленту
Лента вопроса
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.3.2953
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
1.4.3. Ввод неизвестного количества данных
В приведенных выше разделах мы писали программы, которые суммировали числа от 1 до 10. Логическое усовершенствование этой программы подразумевало бы запрос суммируемых чисел у пользователя. В таком случае мы не будем знать, сколько чисел суммировать. Поэтому продолжим читать числа, пока будет что читать.
int sum = 0, value = 0;
// читать данные до конца файла, вычислить сумму всех значений
while (std::cin >> value)
sum += value; // эквивалентно sum = sum + val
Если ввести значения 3 4 5 6, то будет получен результат Sum is: 18.
Первая строка функции main() определяет две переменные типа int по имени sum и value, инициализируемые значением 0. Переменная value применяется для хранения чисел, вводимых в условии цикла while.
while (std::cin >> value)
Условием продолжения цикла while является выражение
Это выражение читает следующее число со стандартного устройства ввода и сохраняет его в переменной value. Как упоминалось в разделе 1.2, оператор ввода возвращает свой левый операнд. Таким образом, в условии фактически проверяется объект std::cin.
Когда объект типа istream используется при проверке условия, результат зависит от состояния потока. Если поток допустим, т.е. не столкнулся с ошибкой и ввод следующего значения еще возможен, это условие считается истинным. Объект типа istream переходит в недопустимое состояние по достижении конца файла (end-of-file) или при вводе недопустимых данных, например строки вместо числа. Недопустимое состояние объекта типа istream в условии свидетельствует о том, что оно ложно.
Таким образом, пока не достигнут конец файла (или не произошла ошибка ввода), условие остается истинным и выполняется тело цикла while. Тело состоит из одного составного оператора присвоения, который добавляет значение переменной value к текущему значению переменной sum. Однажды нарушение условия завершает цикл while. По выходе из цикла выполняется следующий оператор, который выводит значение переменной sum, сопровождаемое манипулятором endl.
Ввод конца файла с клавиатуры
Разные операционные системы используют для конца файла различные значения. Для ввода символа конца файла в операционной системе Windows достаточно нажать комбинацию клавиш (удерживая нажатой клавишу , нажать клавишу ), а затем клавишу или . На машине с операционной системой UNIX, включая Mac OS-X, как правило, используется комбинация клавиш .
Возвращаясь к компиляции
Одной из задач компилятора является поиск ошибок в тексте программ. Компилятор, безусловно, не может выяснить, делает ли программа то, что предполагал ее автор, но вполне способен обнаружить ошибки в форме записи. Ниже приведены примеры ошибок, которые компилятор обнаруживает чаще всего.
Синтаксические ошибки. Речь идет о грамматических ошибках языка С++. Приведенный ниже код демонстрирует наиболее распространенные синтаксические ошибки, снабженные комментариями, которые описывают их суть.
// ошибка: отсутствует ‘)’ список параметров функции main()
// ошибка: после endl используется двоеточие, а не точка с запятой
// ошибка: отсутствуют кавычки вокруг строкового литерала
// ошибка: отсутствует второй оператор вывода
// ошибка: отсутствует ‘;’ после оператора return
Ошибки несовпадения типа. Каждый элемент данных языка С++ имеет тип. Значение 10, например, является числом типа int. Слово «привет» с парными кавычками — это строковый литерал. Примером ошибки несовпадения является передача строкового литерала функции, которая ожидает целочисленным аргумент.
Ошибки объявления. Каждое имя, используемое в программе на языке С++, должно быть вначале объявлено. Использование необъявленного имени обычно приводит к сообщению об ошибке. Типичными ошибками объявления является также отсутствие указания пространства имен, например std. при доступе к имени, определенному в библиотеке, а также орфографические ошибки в именах идентификаторов.
int v1 = 0, v2 = 0;
std::cin >> v >> v2; // ошибка: используется «v» вместо «v1»
// cout не определен, должно быть std::cout
Сообщение об ошибке содержит обычно номер строки и краткое описание того, что компилятор считает неправильным. Исправлять ошибки имеет смысл в том порядке, в котором поступают сообщения о них. Зачастую одна ошибка приводит к появлению других, поэтому компилятор, как правило, сообщает о большем количестве ошибок, чем имеется фактически. Целесообразно также перекомпилировать код после устранения каждой ошибки или небольшого количества вполне очевидных ошибок. Этот цикл известен под названием «редактирование, компиляция, отладка» (edit-compile-debug).
Упражнения раздела 1.4.3
Упражнение 1.16. Напишите собственную версию программы, которая выводит сумму набора целых чисел, прочитанных при помощи объекта cin.