Scanf c описание. Форматированный ввод и вывод

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

В версии С99 к параметру format применен квалификатор restrict.

Управляющая строка, задаваемая параметром format, состоит из символов трех категорий:

  • спецификаторов формата;
  • пробельных символов;
  • символов, отличных от пробельных.

Спецификаторы формата - им предшествует знак процента(%) - сообщают, какого типа данное будет прочитано следующим. Например, спецификатор %s прочитает строку, а %d - целое значение. Строка форматирования читается слева направо, и спецификаторы формата по порядку сопоставляются с аргументами, перечисленными в списке аргументов. Эти коды приведены в следующей таблице.

Код Назначение
Читает значение с плавающей точкой(только С99)
Аналогично коду %a (только С99)
Читает один символ
%d Читает десятичное целое
%i Читает целое в любом формате(десятичное, восьмеричное, шестнадцатеричное)
Читает вещественное число
Аналогично коду %е
%f Читает вещественное число
%F Аналогично коду %f(только С99)
%g Читает вещественное число
%G Аналогично коду %g
Читает восьмеричное число
%s Читает строку
Читает шестнадцатеричное число
%X Аналогично коду %х
Читает указатель
%n Принимает целое значение, равное количеству символов, прочитанных до сих пор
%u Читает десятичное целое без знака
% Просматривает набор символов
%% Читает знак процента

По умолчанию спецификаторы а, f, e и g заставляют функцию scanf() присваивать данные переменным типа float. Если поставить перед одним из этих спецификаторов формата модификатор l, функция scanf() присвоит прочитанное данное переменной типа double. Использование же модификатора L означает, что переменная, принимающая значение, имеет тип long double.

Если вы используете современный компилятор, который поддерживает добавленные в 1995 году средства работы с двухбайтовыми символами, можете задействовать модификатор l применительно к спецификатору с, чтобы обозначить указатель на двухбайтовый символ с типом данных whcar_t. Модификатор l можно также использовать с кодом формата s, чтобы обозначить указатель на строку двухбайтовых символов. Кроме того, модификатор l можно использовать для модификации набора сканируемых двухбайтовых символов.

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

Не пробельный символ в строке форматирования заставляет функцию scanf() прочитать и отбросить соответствующий символ. Например, при использовании строки форматирования %d, %d функция scanf() сначала прочитает целое значение, затем прочитает и отбросит запятую и наконец прочитает еще одно целое. Если заданный символ не обнаружится, работа функции scanf() будет завершена.

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

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

Scanf("%d%d", &r, &c);

примет значения, введенные как 10 20, но наотрез откажется от "блюда", поданного в виде 10,20.

Символ *, стоящий после знака % и перед кодом формата, прочитает данные заданного типа, но запретит их присваивание. Следовательно, оператор

Scanf("%d%*c%d", &х, &у);

при вводе данных в виде 10/20 поместит значение 10 в переменную х, отбросит знак деления и присвоит значение 20 переменной у.

Команды форматирования могут содержать модификатор максимальной длины поля. Он представляет собой целое число, располагаемое между знаком % и кодом формата, которое ограничивает количество символов, читаемых для любого поля. Например, если вы хотите прочитать в переменную address не более 20 символов, используйте следующий оператор.

Scanf("%20s", address);

Если входной поток содержит более 20 символов, то при последующем обращении к операции ввода чтение начнется с того места, в котором "остановился" предыдущий вызов функции scanf(). При обнаружении пробельного символа ввод данных для поля может завершиться до достижения максимальной длины поля. В этом случае функция scanf() переходит к чтению следующего поля.

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

Scanf("%с%с%с", &а, &Ь, &с);

поместит символ х в переменную а, пробел - в переменную Ь и символ у - в переменную с.

Помните, что любые другие символы управляющей строки, не являющиеся спецификаторами формата(включая пробелы, символы табуляции и новой строки), используются для установления соответствия и отбрасывания символов из входного потока. Например, если поток ввода выглядит, как 10t20, оператор

Scanf("%st%s", &х, &у);

поместит 10 в переменную х и 20 - в переменную у. Символ t отбрасывается, так как он присутствует в управляющей строке.

Еще один способ использования функции scanf() называется набором сканируемых символов(scanset). В этом случае определяется набор символов, которые могут быть прочитаны функцией scanf() и присвоены соответствующему массиву символов. Для определения такого набора необходимо заключить символы, подлежащие сканированию, в квадратные скобки. Открывающая квадратная скобка должна следовать сразу за знаком процента. Например, следующий набор сканируемых символов говорит о том, что необходимо прочитать только символы А, В и С.

%[АВС]

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

Если первый символ в наборе является знаком вставки(^), то получаем обратный эффект: входное поле читается до первого символа из заданного набора символов, т.е. знак вставки заставляет функцию scanf() принимать любые символы, которые не определены в наборе.

Многие компиляторы позволяют с помощью дефиса задать диапазон. Например, следующий оператор заставляет функцию scanf() принимать символы от А до Z.

Важно помнить, что набор сканируемых символов различает прописные и строчные буквы. Следовательно, если вы хотите сканировать как прописные, так и строчные буквы, задайте их отдельно.

Функция scanf() возвращает число, равное количеству полей, для которых были успешно присвоены значения. К этим полям не относятся поля, которые были прочитаны, но присвоение не состоялось в связи с использованием модификатора * для подавления присваивания. При обнаружении ошибки до присвоения значения первого поля функция scanf() возвращает значение EOF.

Модификаторы формата, добавленные к функции scanf() стандартом С99

В версии С99 добавлено несколько модификаторов формата для использования в функции scanf(): hh, ll, j, z и t. Модификатор hh можно применять к спецификаторам d, i, о, и, х и п. Он означает, что соответствующий аргумент является указателем на значение типа signed char или unsigned char. Модификатор ll также можно применять к спецификаторам d, i, о, и, х и п. Он означает, что соответствующий аргумент является указателем на значение типа signed long long int или unsigned long long int.

Модификатор формата j, который применяется к спецификаторам d, i, о, и, х и n, означает, что соответствующий аргумент является указателем на значение типа intmax_t или uintmax_t. Эти типы объявлены в заголовке и служат для хранения целых максимально возможной длины.

Модификатор формата z, который применяется к спецификаторам d, i, о, u, x и n, означает, что соответствующий аргумент является указателем на объект типа size_t. Этот тип объявлен в заголовке и служит для хранения результата операции sizeof.

Модификатор формата t, который применяется к спецификаторам d, i, о, u, x и n, означает, что соответствующий аргумент является указателем на объект типа ptrdiff_t. Этот тип объявлен в заголовке и служит для хранения значения разности между двумя указателями.

Функция printf() позволяет выводить информацию на экран при программировании в консольном режиме. Данная функция определена в библиотеке stdio.h и имеет следующий синтаксис:

int printf(const char *format [, argument]...);

Здесь первый аргумент *format определяет строку, которая выводится на экран и может содержать специальные управляющие символы для вывода переменных. Затем, следует список необязательных аргументов, которые поясняются ниже. Функуция возвращает либо число отображенных символов, либо отрицательное число в случае своей некорректной работы.

В самой простой реализации функция printf() просто выводит заданную строку на экран монитора:

printf(“Привет мир.”);

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

int num;
num = 5;
printf(“%d”, num);

В первых двух строках данной программы задается переменная с именем num типа int. В третьей строке выполняется вывод переменной на экран. Работа функции printf() выглядит следующим образом. Сначала функция анализирует строку, которую необходимо вывести на экран. В данном случае это «%d». Если в этой строке встречается спецификатор, то на его место записывается значение переменной, которая является вторым аргументом функции printf(). В результате, вместо исходной строки «%d» на экране появится строка «5», т.е. будет выведено число 5.

Следует отметить, что спецификатор «%d» выводит только целочисленные типы переменных, например int. Для вывода других типов следует использовать другие спецификаторы. Ниже перечислены основные виды спецификаторов:

%с – одиночный символ
%d – десятичное целое число со знаком
%f – число с плавающей точкой (десятичное представление)
%s – строка символов (для строковых переменных)
%u – десятичное целое без знака
%% - печать знака процента

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

int num_i;
float num_f;
num_i = 5;
num_f = 10.5;
printf(“num_i = %d, num_f = %f”, num_i, num_f);

Результат выполнения программы будет выглядеть так:

num_i = 5, num_f = 10.5

Кроме спецификаторов в функции printf() используются управляющие символы, такие как перевод строки \n, табуляции \t и др. Например, если в ранее рассмотренном примере необходимо вывести значения переменных не в строчку, а в столбик, то необходимо переписать функцию printf() следующим образом:

printf(“num_i = %d,\n num_f = %f”, num_i, num_f);

Аналогично используется и символ табуляции.

Для ввода информации с клавиатуры удобно использовать функцию scanf() библиотеки stdio.h, которая имеет следующий синтаксис:

int scanf(const char *format [,argument]...);

Здесь, как и для функции printf(), переменная *format определяет форматную строку для определения типа вводимых данных и может содержать те же спецификаторы что и функция printf(). Затем, следует список необязательных аргументов. Работа функции scanf() демонстрируется на листинге 1.4.

Листинг 1.4. Пример использования функции scanf().

#include
int main()
{
int age;
float weight;
printf(“Введите информацию о Вашем возрасте: ”);
scanf(“%d”, &age);
printf(“Введите информацию о Вашем весе: ”);
scanf(“%f”, &weigth);
printf(“Ваш возраст = %d, Ваш вес = %f”, age, weigth);

Return 0;
}

Основным отличием применения функции scanf() от функции printf() является знак & перед именем переменной, в которую записываются результаты ввода.

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

scanf(“ %d, %d ”, &n, &m);

Функция scanf() интерпретирует это так, как будто ожидает, что пользователь введет число, затем – запятую, а затем – второе число. Все происходит так, как будто требуется ввести два целых числа следующим образом:

Функция scanf() возвращает число успешно считанных элементов. Если операции считывания не происходило, что бывает в том случае, когда вместо ожидаемого цифрового значения вводится какая-либо буква, то возвращаемое значение равно 0.

Стандартная библиотека C/C++ включает ряд функций для чтения и записи на консоли (клавиатура и монитор). Эти функции читают и пишут данные как простой поток символов.

Понятие потока (stream), использованное в программировании, тесно связано с обычным, бытовым пониманием этого слова. Поток ввода можно сравнить с трубой, по которой вода (информация) поступает в бассейн (память компьютера), поток вывода - с трубой, по которой вода выходит из бассейна. Важной особенностью этой трубы является то, что в каждый момент времени данные могут двигаться только в одном направлении. Даже если одна и та же труба используется для ввода и вывода, это не может происходить одновременно: для переключения направления потока его нужно остановить, выполнить некие действия и лишь затем направить поток в обратном направлении. Другой особенностью потока является то, что он почти никогда не иссякает. Иногда он высыхает, но этот период не может быть долгим, если система функционирует нормально.

Функция стандартного вывода printf()

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

Функция printf() имеет прототип в файле stdio.h
int printf(char *управляющая строка, ...);

В случае успеха функция printf() возвращает число выведенных символов.

Управляющая строка содержит два типа информации: символы, которые непосредственно выводятся на экран, и спецификаторы формата, определяющие, как выводить аргументы.

Функция printf() это функция форматированного вывода. Это означает, что в параметрах функции необходимо указать формат данных, которые будут выводиться. Формат данных указывается спецификаторами формата. Спецификатор формата начинается с символа % за которым следует код формата.

Спецификаторы формата:

символ
%d целое десятичное число
%i целое десятичное число
%e десятичное число в виде x.xx e+xx
%E десятичное число в виде x.xx E+xx
%f
%F десятичное число с плавающей запятой xx.xxxx
%g %f или %e, что короче
%G %F или %E, что короче
%o восьмеричное число
%s строка символов
%u беззнаковое десятичное число
%x шестнадцатеричное число
%X шестнадцатеричное число
%% символ %
%p указатель
%n указатель

Кроме того, к командам формата могут быть применены модификаторы l и h.

%ld печать long int
%hu печать short unsigned
%Lf печать long double

В спецификаторе формата, после символа % может быть указана точность (число цифр после запятой). Точность задаётся следующим образом: %.n<код формата>. Где n - число цифр после запятой, а <код формата> - один из кодов приведённых выше.

Например, если у нас есть переменная x=10.3563 типа float и мы хотим вывести её значение с точностью до 3-х цифр после запятой, то мы должны написать:

printf("Переменная x = %.3f",x);

Результат:
Переменная x = 10.356

Вы также можете указать минимальную ширину поля отводимого для печати. Если строка или число больше указанной ширины поля, то строка или число печатается полностью.

Например, если вы напишите:

printf("%5d",20);

то результат будет следующим:
20

Обратите внимание на то, что число 20 напечаталось не с самого начала строки. Если вы хотите чтобы неиспользованные места поля заполнялись нулями, то нужно поставить перед шириной поля символ 0.

Например:

printf("%05d",20);

Результат:
00020

Кроме спецификаторов формата данных в управляющей строке могут находиться управляющие символы:

\b BS, забой
\f Новая страница, перевод страницы
\n Новая строка, перевод строки
\r Возврат каретки
\t Горизонтальная табуляция
\v Вертикальная табуляция
\" Двойная кавычка
\" Апостроф
\\ Обратная косая черта
\0 Нулевой символ, нулевой байт
\a Сигнал
\N Восьмеричная константа
\xN Шестнадцатеричная константа
\? Знак вопроса

Чаще всего вы будете использовать символ \n. С помощью этого управляющего символа вы сможете переходить на новую строку. Посмотрите примеры программ и вы всё поймёте.

Примеры программ.

/* Пример 1 */
#include

void main(void)
{
int a,b,c; // Объявление переменных a,b,c
a=5;
b=6;
c=9;
printf("a=%d, b=%d, c=%d",a,b,c);
}

Результат работы программы:
a=5, b=6, c=9

/* Пример 2 */
#include

void main(void)
{
float x,y,z;

X=10.5;
y=130.67;
z=54;

Printf("Координаты объекта: x:%.2f, y:%.2f, z:%.2f", x, y, z);
}

Результат работы программы:
Координаты объекта: x:10.50, y:130.67, z:54.00

/* Пример 3 */
#include

void main()
{
int x;

X=5;
printf("x=%d", x*2);
}

Результат работы программы:
x=10

/* Пример 4 */
#include

void main(void)
{
printf("\"Текст в кавычках\"");
printf("\nСодержание кислорода: 100%%");
}

Результат работы программы:
"Текст в кавычках"
Содержание кислорода: 100%

/* Пример 5 */
#include

void main(void)
{
int a;

A=11; // 11 в десятичной равно b в шестнадцатеричной
printf("a-dec=%d, a-hex=%X",a,a);
}

Результат работы программы:
a-dec=11, a-hex=b

/* Пример 6 */
#include

void main(void)
{
char ch1,ch2,ch3;

Ch1="A";
ch2="B";
ch3="C";

Printf("%c%c%c",ch1,ch2,ch3);
}

Результат работы программы:
ABC

/* Пример 7 */
#include

void main(void)
{
char *str="Моя строка.";

Printf("Это %s",str);
}

Результат работы программы:
Это Моя строка.

/* Пример 8 */
#include

void main(void)
{
printf("Здравствуйте!\n"); // После печати будет переход на новую строку - \n
printf("Меня зовут Павел."); // Это будет напечатано на новой строке
}

Результат работы программы:
Здравствуйте!
Меня зовут Павел.

Функция стандартного ввода scanf()

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

Функция scanf() имеет следующий прототип в файле stdio.h:
int scanf(char *управляющая строка);

Функция возвращает число переменных которым было присвоено значение.

Управляющая строка содержит три вида символов: спецификаторы формата, пробелы и другие символы. Спецификаторы формата начинаются с символа %.

Спецификаторы формата:

При вводе строки с помощью функции scanf() (спецификатор формата %s), строка вводиться до первого пробела!! т.е. если вы вводите строку "Привет мир!" с использованием функции scanf()


scanf("%s",str);

то после ввода результирующая строка, которая будет храниться в массиве str будет состоять из одного слова "Привет". ФУНКЦИЯ ВВОДИТ СТРОКУ ДО ПЕРВОГО ПРОБЕЛА! Если вы хотите вводить строки с пробелами, то используйте функцию

char *gets(char *buf);

С помощью функции gets() вы сможете вводить полноценные строки. Функция gets() читает символы с клавиатуры до появления символа новой строки (\n). Сам символ новой строки появляется, когда вы нажимаете клавишу enter. Функция возвращает указатель на buf. buf - буфер (память) для вводимой строки.

Хотя gets() не входит в тему этой статьи, но всё же давайте напишем пример программы, которая позволяет ввести целую строку с клавиатуры и вывести её на экран.

#include

void main(void)
{
char buffer; // массив (буфер) для вводимой строки

Gets(buffer); // вводим строку и нажимаем enter
printf("%s",buffer); // вывод введённой строки на экран
}

Ещё одно важное замечание! Для ввода данных с помощью функции scanf(), ей в качестве параметров нужно передавать адреса переменных, а не сами переменные. Чтобы получить адрес переменной, нужно поставить перед именем переменной знак &(амперсанд). Знак & означает взятие адреса.

Что значит адрес? Попробую объяснить. В программе у нас есть переменная. Переменная хранит своё значение в памяти компьютера. Так вот адрес, который мы получаем с помощью & это адрес в памяти компьютера где храниться значение переменной.

Давайте рассмотрим пример программы, который показывает нам как использовать &

#include

void main(void)
{
int x;

Printf("Введите переменную x:");
scanf("%d",&x);
printf("Переменная x=%d",x);
}

Теперь давайте вернёмся к управляющей строке функции scanf(). Ещё раз:

int scanf(char *управляющая строка);

Символ пробела в управляющей строке дает команду пропустить один или более пробелов в потоке ввода. Кроме пробела может восприниматься символ табуляции или новой строки. Ненулевой символ указывает на чтение и отбрасывание этого символа.

Разделителями между двумя вводимыми числами являются символы пробела, табуляции или новой строки. Знак * после % и перед кодом формата (спецификатором формата) дает команду прочитать данные указанного типа, но не присваивать это значение.

Например:

scanf("%d%*c%d",&i,&j);

при вводе 50+20 присвоит переменной i значение 50, переменной j - значение 20, а символ + будет прочитан и проигнорирован.

В команде формата может быть указана наибольшая ширина поля, которая подлежит считыванию.

Например:

scanf("%5s",str);

указывает необходимость прочитать из потока ввода первые 5 символов. При вводе 1234567890ABC массив str будет содержать только 12345, остальные символы будут проигнорированы. Разделители: пробел, символ табуляции и символ новой строки - при вводе символа воспринимаются, как и все другие символы.

Если в управляющей строке встречаются какие-либо другие символы, то они предназначаются для того, чтобы определить и пропустить соответствующий символ. Поток символов 10plus20 оператором

scanf("%dplus%d",&x,&y);

присвоит переменной x значение 10, переменной y - значение 20, а символы plus пропустит, так как они встретились в управляющей строке.

Одной из мощных особенностей функции scanf() является возможность задания множества поиска (scanset). Множество поиска определяет набор символов, с которыми будут сравниваться читаемые функцией scanf() символы. Функция scanf() читает символы до тех пор, пока они встречаются в множестве поиска. Как только символ, который введен, не встретился в множестве поиска, функция scanf() переходит к следующему спецификатору формата. Множество поиска определяется списком символов, заключённых в квадратные скобки. Перед открывающей скобкой ставиться знак %. Давайте рассмотрим это на примере.

#include

void main(void)
{
char str1, str2;
scanf("%%s", str1, str2);
printf("\n%s\n%s",str1,str2);
}
Введём набор символов:
12345abcdefg456

На экране программа выдаст:
12345
abcdefg456

При задании множества поиска можно также использовать символ "дефис" для задания промежутков, а также максимальную ширину поля ввода.

scanf("%10", str1);

Можно также определить символы, которые не входят в множество поиска. Перед первым из этих символов ставиться знак ^. Множество символов различает строчные и прописные буквы.

Напомню, что при использовании функции scanf(), ей в качестве параметров нужно передавать адреса переменных. Выше был написан код:

char str; // массив на 80 символов
scanf("%s",str);

Обратите внимание на то, что перед str не стоит символ &. Это сделано потому, что str является массивом, а имя массива - str является указателем на первый элемент массива. Поэтому знак & не ставиться. Мы уже передаем функции scanf() адрес. Ну проще говоря str это адрес в памяти компьютера где будет храниться значение первого элемента массива.

Примеры программ.

Пример 1.
Эта программа выводит на экран запрос "Сколько вам лет?:" и ждёт ввода данных. Если, например, ввести число 20, то программа выведет строку "Вам 20 лет.". При вызове функции scanf(), перед переменной age мы поставили знак &, так как функции scanf() нужны адреса переменных. Функция scanf() запишет введённое значение по указанному адресу. В нашем случае введённое значение 20 будет записано по адресу переменной age.

/* Пример 1 */

#include

void main(void)
{
int age;

Printf("\nСколько вам лет?:");
scanf("%d",&age);
printf("Вам %d лет.", age);
}

Пример 2.
Программа калькулятор. Этот калькулятор может только складывать числа. При вводе 100+34 программа выдаст результат: 100+34=134.

/* Пример 2 */

#include

void main(void)
{
int x, y;

Printf("\nКалькулятор:");
scanf("%d+%d", &x, &y);
printf("\n%d+%d=%d", x, y, x+y);
}

Пример 3.
Этот пример показывает как установить ширину поля считывания. В нашем примере ширина поля равна пяти символам. Если вы введёте строку с большим количеством символов, то все символы после 5-го будут отброшены. Обратите внимание на вызов функции scanf(). Знак & не стоит перед именем массива name так как имя массива name является адресом первого элемента массива.

/* Пример 3 */

#include

void main(void)
{
char name;

Printf("\nВведите ваш логин (не более 5 символов):");
scanf("%5s", name);
printf("\nВы ввели %s", name);
}

Пример 4.
Последний пример в этой статье показывает как можно использовать множество поиска. После запуска программы введите число от 2 до 5.

/* Пример 4 */

#include

void main(void)
{
char bal;

Printf("Ваша оценка 2,3,4,5:");
scanf("%", &bal);
printf("\nОценка %c", bal);
}

В данной статье функция scanf() рассматривается в общем виде без привязки к конкретному стандарту, поэтому сюда включены данные из любых стандартов C99, C11, C++11, C++14. Возможно, в некоторых стандартах функция работает с отличиями от изложенного в статье материала.

Функция scanf C - описание

scanf() - это функция, расположенная в заголовочном файле stdio.h(C) и cstdio(C++), она также называется форматированным вводом данных в программу. scanf читает символы из стандартного потока ввода (stdin) и преобразует их в соответствии с форматом, после чего записывает в указанные переменные. Формат - означает, что данные при поступлении приводятся к определенному виду. Таким образом, функция scanf C описывается:

scanf("%формат", &переменная1[, &переменная2,[…]]),

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

Некоторые программисты из-за аналогии с другими языками называют функции, подобные scanf() или printf(), процедурами.

Scanf позволяет осуществлять ввод всех базовых типов языка: char, int, float, string и т.д. В случае с переменными типа string нет нужды указывать знак адреса - «&», так как переменная типа string является массивом, и имя ее является адресом первого элемента массива в памяти компьютера.

Формат ввода данных или управляющая строка

Начнем с рассмотрения примера использования функции scanf C из описания.

#include int main() { int x; while (scanf("%d", &x) == 1) printf("%d\n", x); return 0; //требование linux-систем }

Формат ввода состоит из следующих четырех параметров: %[*][ширина][модификаторы] тип. При этом знак «%» и тип являются обязательными параметрами. То есть, минимальный вид формата выглядит следующим образом: “%s”, “%d” и так далее.

В общем случае символы, составляющие строку формата, делятся на:

  • спецификаторы формата - все, что начитается с символа %;
  • разделительные или пробельные символы - ими считаются пробел, табуляция(\t), новая строка (\n);
  • символы, отличающиеся от пробельных.

Функция может оказаться небезопасной.

Используйте вместо scanf() функцию scanf_s().

(сообщение от Visual Studio)

Тип, или спецификаторы формата, или литеры преобразования, или контролирующие символы

Описание scanf C обязано содержать, как минимум, спецификатор формата, который указывается в конце выражений, начинающихся со знака «%». Он сообщает программе тип данных, который следует ожидать при вводе, обычно с клавиатуры. Список всех спецификаторов формата в таблице ниже.

Значение

Программа ожидает ввод символа. Переменная для записи должна иметь символьный тип char.

Программа ожидает ввод десятичного числа целого типа. Переменная должна иметь тип int.

Программа ожидает ввод числа с плавающей точкой (запятой) в экспоненциальной форме. Переменная должна иметь тип float.

Программа ожидает ввод числа с плавающей точкой (запятой). Переменная должна иметь тип float.

7

Программа ожидает ввод числа с плавающей точкой (запятой). Переменная должна иметь тип float.

Программа ожидает ввод восьмеричного числа. Переменная должна иметь тип int.

Программа ожидает ввод строки. Строкой считается набор любых символов до первого встреченного разделительного символа. Переменная должна иметь тип string.

Программа ожидает ввод шестнадцатеричного числа. Переменная должна иметь тип int.

Переменная ожидает ввод указателя. Переменная должна иметь тип указателя.

Записывает в переменную целое значение, равное количеству считанных до текущего момента символов функцией scanf.

Программа считывает беззнаковое целое число. Тип переменной должен быть unsigned integer.

Программа ожидает ввод двоичного числа. Переменная должна иметь тип int.

Набор сканируемых символов. Программа ожидает ввод символов, из ограниченного пула, указанного между scanf будет работать до тех пор, пока на потоке ввода находятся символы из указанного множества.

Символы в строке формата

Символ звездочка (*)

Звездочка (*) - это флаг, указывающий, что операцию присвоения надо подавить. Звездочка ставится сразу после знака «%». Например,

Scanf("%d%*c%d", &x, &y); //игнорировать символ между двумя целыми числами. scanf("%s%*d%s", str, str2); //игнорировать целое число, между двумя строками.

То есть, если ввести в консоли строку «45-20» программа сделает следующее:

  1. Переменной «x» будет присвоено значение 45.
  2. Переменной «y» будет присвоено значение 20.
  3. А знак минус(тире) «-» будет проигнорирован благодаря «%*c».

Ширина (или ширина поля)

Это целое число между знаком «%» и спецификатором формата, которое определяет максимальное количество символов для считывания за текущую операцию чтения.

Следует иметь в виду несколько важных моментов:

  1. scanf прекратит свою работу, если встретит разделительный символ, даже если не считал 20 символов.
  2. Если на ввод подается больше 20 символов, в переменную str будут записаны только первые 20 из них.

Модификаторы типа (или точность)

Это специальные флаги, которые модифицируют тип данных, ожидаемых к вводу. Флаг указывается слева от спецификатора типа:

  • L или l (маленькая L) При использовании «l» со спецификаторами d, i, o, u, x, флаг сообщает программе, что ожидается ввод данных типа long int. При использовании «l» со спецификатором e или f, флаг сообщает программе, что она должна ожидать ввод значения типа double. Использование «L» сообщает программе, что ожидается значение типа long double. Использование «l» со спецификаторами «c» и «s» сообщает программе, что ожидаются двухбайтовые символы типа wchar_t. Например, "%lc", "%ls", "%l".
  • h - флаг, указывающий на тип short.
  • hh - обозначает, что переменная является указателем на значение типа signed char или unsigned char. Флаг можно использовать со спецификаторами d, i, o, u, x, n.
  • ll (две маленькие L) - обозначает, что переменная является указателем на значение типа signed int или unsigned long long int. Флаг используется со спецификаторами: d, i, o, u, x, n.
  • j - обозначает, что переменная является указателем на тип intmax_t или uintmax_t из заголовочного файла stdint.h. Используется со спецификаторами: d, i, o, u, x, n.
  • z - обозначает, что переменная является указателем на тип size_t, определение которого находится в stddef.h. Используется со спецификаторами: d, i, o, u, x, n.
  • t - обозначает, что переменная является указателем на тип ptrdiff_t. Определение на этот тип находится в stddef.h. Используется со спецификаторами: d, i, o, u, x, n.

Более явно картину с модификаторами можно представить в виде таблицы. Такое описание scanf C для програмистов будет понятнее.

Остальные символы

Любые символы, которые будут встречены в формате, будут отбрасываться. При этом стоит отметить, что наличие в управляющей строке пробельных или разделительных символов (новая строка, пробел, табуляция) может приводить к разному поведению функции. В одной версии scanf() будет читать без сохранения любое количество разделителей до момента, пока не встретит символ, отличный от разделителя, а в другой версии - пробелы (только они) не играют роли и выражение "%d + %d" эквивалентно "%d+%d".

Примеры

Рассмотрим ряд примеров, позволяющих поразмыслить и точнее понять работу функции.

Scanf("%3s", str); //если ввести в консоли строку «1d2s3d1;3», в str запишется только «1d2» scanf("%dminus%d", &x, &y); //символы «minus» между двумя числами будут отброшены scanf("%5", str); //ввод символов в str будет происходить до тех пор, пока их не будет 5 и символы являются числами от 0 до 9. scanf("%lf", &d); //ожидается ввод данных типа double scanf("%hd", &x); //ожидается число типа short scanf("%hu", &y); //ожидается число типа unsigned short scanf("lx", &z); //ожидается число типа long int

Из приведенных примеров видно, как меняется ожидаемое число с использованием различных символов.

scanf C - описание для начинающих

Данный раздел будет полезен новичкам. Зачастую нужно иметь под рукой не столько полное описание scanf C, сколько детали работы функции.

  • Функция является отчасти устаревшей. Существует несколько разных реализаций в библиотеках различных версий. Например, усовершенствованная функция scanf S C, описание которой можно найти на сайте microsoft.
  • Количество спецификаторов в формате должно соответствовать количеству переданных функции аргументов.
  • Элементы входного потока должны отделяться только разделительными символами: пробел, табуляция, новая строка. Запятая, точка с запятой, точка и т. д. - эти символы не являются разделительными для функции scanf().
  • Если scanf встретит разделительный символ, ввод будет остановлен. Если переменных для чтения больше одной, то scanf перейдет к чтению следующей переменной.
  • Малейшее несоответствие формата вводимых данных приводит к непредсказуемым результатам работы программы. Хорошо, если программа просто завершится с ошибкой. Но нередко программа продолжает работать и делает это неверно.
  • scanf("%20s …", …); Если входной поток превышает 20 символов, то scanf прочитает первые 20 символов и, либо прекратит работу, либо перейдет к чтению следующей переменной, если она указана. При этом следующий вызов scanf продолжит чтение входного потока с того места, где остановилась работа предыдущего вызова scanf. Если при чтении первых 20 символов будет встречен разделительный символ, scanf прекратит свою работу или перейдет к чтению следующей переменной, даже если не считал 20 символов для первой переменной. При этом все несчитанные символы прицепятся к следующей переменной.
  • Если набор сканируемых символов начать со знака «^», то scanf будет читать данные до тех пор, пока не встретит разделительный символ или символ из набора. Например, "%[^A-E1-5]" будет считывать данные из потока, пока не будет встречен один из символов английского алфавита от А до Е в верхнем регистре или одно из чисел от 1 до 5.
  • Функция scanf C по описанию возвращает число, равное успешному количеству записей в переменные. Если scanf записывает 3 переменные, то результатом успешной работы функции будет возврат числа 3. Если scanf не смог записать ни одной переменной, то результат будет 0. И, наконец, если scanf вообще не смог начать работать по каким-либо причинам, результатом будет EOF.
  • Если функция scanf() завершила свою работу некорректно. Например, scanf("%d", &x) - ожидалось число, а на ввод пришли символы. Следующий вызов scanf() начнет свою работу с того места в потоке ввода, где завершился предыдущий вызов функции. Чтобы преодолеть эту проблему, необходимо избавиться от проблемных символов. Это можно сделать, например, вызвав scanf("%*s"). То есть, функция прочитает строку символов и выбросит ее. Таким хитрым образом можно продолжить ввод нужных данных.
  • В некоторых реализациях scanf() в наборе сканируемых символов недопустимо использование «-».
  • Спецификатор “%c” читает каждый символ из потока. То есть символ -разделитель он также читает. Чтобы пропустить символ разделитель и продолжить читать нужный символ, можно использовать “%1s”.
  • При использовании спецификатора «c» допустимо использовать ширину “%10c”, однако тогда в виде переменной функции scanf нужно передать массив элементов типа char.
  • “%” - это значит "все маленькие буквы английского алфавита", а “%” - значит просто 3 символа: ‘z’, ‘a’, ‘-’. Иными словами, символ «-» означает диапазон только в том случае, если стоит между двумя символами, которые находятся в правильном порядке следования. Если «-» находится в конце выражения, в начале или в неверном порядке символов по обеим сторонам от них, то он представляет собой просто символ дефиса, а не диапазон.

Заключение

На этом завершается описание scanf C. Это хорошая удобная функция для работы в небольших программах и при использовании процедурного метода программирования. Однако главным недостатком является количество непредсказуемых ошибок, которые могут возникнуть при использовании scanf. Поэтому, описание scanf C при програмировании лучше всего держать перед глазами. В крупных профессиональных проектах используются потоки iostream, ввиду того, что обладают более высокоуровневыми возможностями, лучше позволяют отлавливать и обрабатывать ошибки, а также работать со значительными объемами информации. Также следует отметить, описание scanf C на русском доступно на сетевых многих источниках, как и примеры ее использования, ввиду возраста функции. Поэтому при необходимости всегда можно найти ответ на тематических форумах.

Теги: Форматированный ввод, форматированный вывод, printf, scanf, fgets, getch, строка формата, спецификатор формата, флаги, управляющие символы.

Форматированный вывод

Сегодня мы рассмотрим две важные функции форматированного ввода и вывода. Устройство и работу этих функций полностью можно понять только после изучения работы с указателями и функций с переменным числом параметров. Но пользоваться этими функциями необходимо уже сейчас, так что некоторые моменты придётся пропустить.

Функция форматированного вывода printf получает в качестве аргументов строку формат и аргументы, которые необходимо вывести в соответствии с форматом, и возвращает число выведенных символов. В случае ошибки возвращает отрицательное значение и устанавливает значение ferror. Если произошло несколько ошибок, errno равно EILSEQ.
int printf (const char * format, ...);

#include #include void main() { //функция не получает никаких аргументов, кроме строки printf("Hello world"); getch(); }

Функция проходит по строке и заменяет первое вхождение % на первый аргумент, второе вхождение % на второй аргумент и т.д. Далее мы будем просто рассматривать список флагов и примеры использования.

Общий синтаксис спецификатора формата
%[флаги][ширина][.точность][длина]спецификатор
Спецификатор – это самый важный компонент. Он определяет тип переменной и способ её вывода.

Таб. 1 Спецификатор типа.
Спецификатор Что хотим вывести Пример
d или i Целое со знаком в в десятичном виде 392
u Целое без знака в десятичном виде 7235
o Беззнаковое в восьмеричном виде 657
x Беззнаковое целое в шестнадцатеричном виде 7fa
X Беззнаковое целое в шестнадцатеричном виде, верхний регистр 7FA
f или F Число с плавающей точкой 3.4563745
e Экспоненциальная форма для числа с плавающей точкой 3.1234e+3
E Экспоненциальная форма для числа с плавающей точкой, верхний регистр 3.1234E+3
g Кратчайшее из представлений форматов f и e 3.12
G Кратчайшее из представлений форматов F и E 3.12
a Шестнадцатеричное представление числа с плавающей точкой -0xc.90fep-2
A Шестнадцатеричное представление числа с плавающей точкой, верхний регистр -0xc.90FEP-2
c Буква a
s Строка (нуль-терминированный массив букв) Hello World
p Адрес указателя b8000000
n Ничего не пачатает. Аргументом должен быть указатель на signed int. По этому адресу будет сохранено количество букв, которое было выведено до встречи %n
% Два идущих друг за другом процента выводят знак процента %

#include #include void main() { int a = 0x77, b = -20; char c = "F"; float f = 12.2341524; double d = 2e8; char* string = "Hello, World!"; printf("%s\n", string); printf("a = %d, b = %d\n", a, b); printf("a = %u, b = %u\n", a, b); printf("a = %x, b = %X\n", a, b); printf("dec a = %d, oct a = %o, hex a = %x\n", a, a, a); printf("floating point f = %f, exp f = %e\n", f, f); printf("double d = %f or %E\n", d, d); printf("not all compiler support %a\n", f); printf("character c = %c, as number c = %d", c, c); printf("address of string is %p", string); getch(); }

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

Таб. 4 Точность.
.Точность Описание
.число Для спецификаторов целых (d, i, o, u, x, X) точность определяет минимальное количество знаков, которое необходимо вывести. Если значение короче, то выводятся нули перед числом. Значение не обрезается, даже если оно длиннее. Точночть 0 означает, что для значения 0 ничего не выводится.
Для спецификаторов чисел с плавающей точкой (a, A, e, E, f, F) это число знаков, которые необходимо вывести после десятичной точки (по умолчанию 6).
Для g и G - это число значащих разрядов, которые необходимо вывести.
Для s - выводится указанное число символов. По умолчанию выводятся все символы до первого нулевого.
Если число не стоит, то по умолчанию точность равна 0
.* Точность не указана в строке формата, она передаётся отдельно в виде аргумента, который должен предшествовать выводимому числу

#include #include void main() { int a = 0x77, b = -20; char c = "F"; float f = 12.2341524; double d = 2e2; char* string = "Hello, World!"; printf("%.3f\n", f); printf("%.*f\n", 2, f); printf("%010.3f\n", d); printf("%*d\n", 6, a); printf("%+d\n", b); printf("%0.6d\n", a); printf("%.f\n", d); printf("%.4s", string); getch(); }

Суб-спецификатор длины изменяет длину типа. В случае, если длина не совпадает с типом, по возможности происходит преобразование до нужного типа.

Таб. 5 Длина.
спецификаторы
Длина d, i u o x X f F e E g G a A c s p n
(none) int unsigned int double int char* void* int*
hh signed char unsigned char signed char*
h short int unsigned short int short int*
l long int unsigned long int wint_t wchar_t* long int*
ll long long int unsigned long long int long long int*
j intmax_t uintmax_t intmax_t*
z size_t size_t size_t*
t ptrdiff_t ptrdiff_t ptrdiff_t*
L long double

#include #include void main() { long long x = 12300000000579099123; short i = 10; printf("%llu\n", x); printf("%d\n", i); printf("%hd\n", i); getch(); }

Форматированный ввод

Рассмотрим форматированный ввод функцией scanf.
int scanf(const char*, ...)
Функция принимает строку формата ввода (она похожа на строку формата printf) и адреса, по которым необходимо записать считанные данные. Возвращает количество успешно проинициализированных аргументов.
Формат спецификатора ввода
%[*][ширина][длинна]спецификатор

Таб. 6 Спецификатор типа.
Спецификатор Описание Выбранные символы
i, u Целые Произвольное число цифр (0-9), возможно, начинающихся с + или -. Если число начинается с 0, то считывается в восьмеричном формате, если с 0x, то в шестнадцатеричном.
d Десятичное целое Произвольное число цифр (0-9), возможно, начинающихся с + или -.
o восьмеричное целое Произвольное число цифр (0-7), возможно, начинающихся с + или -.
x Шестнадцатеричное целое Произвольное число цифр (0-F), возможно, начинающихся с + или - и префикса 0x или 0X.
f, e, g Число с плавающей точкой Число, состоящее из набора цифр 0-9, возможно с десятичным разделителем (точкой). Возможно также представление в экспоненциальной форме. C99 позволяет также вводить число в шестнадцатеричном формате.
a
c Символ Если ширина не передана, то считывает один символ. Если ширина передана, то считывает нужное количество символов и размещает их в массиве БЕЗ терминального символа на конце.
s Строка Считывает все не пробельные символы. Если указана ширина, то не более n символов. Ставит на место n+1 символа терминальный.
p Адрес указателя Последовательность символов, трактуемая как адрес указателя. Формат зависит от реализации, но совпадает с тем, как выводит printf с ключом p
[символы] Множество символов Считывает только те символы, которые записаны в квадратных скобках, С99
[^символы] Множество символов Считывает только те символы, которые не указаны в квадратных скобках, С99
n Ничего не считывает Сохраняет число уже считанных символов по указанному адресу

Как и в printf, ширина, заданная символом * ожидает аргумента, который будт задавать ширину. Флаг длина совпадает с таким флагом функции printf.

#include #include void main() { int year, month, day; char buffer; int count; //Требует форматированного ввода, например 2013:12:12 printf("Enter data like x:x:x = "); scanf("%d:%d:%d", &year, &month, &day); printf("year = %d\nmonth = %d, day = %d\n", year, month, day); //Считываем строку, не более 127 символов. При считывании в массив писать & не надо, //так как массив подменяется указателем printf("Enter string = "); scanf("%127s", buffer); printf("%s", buffer); getch(); }

Кроме функций scanf и printf есть ещё ряд функций, которые позволяют получать вводимые данные

int getch() - возвращает введённый символ, при этом не выводит его на консоль. #include #include void main() { char c = 0; do { c = getch(); printf("%c", c); } while (c != "q"); }

char * fgets (char * str, int num, FILE * stream) - функция позволяет считывать строку с пробельными символами. Несмотря на то, что она работает с файлом, можно с её помощью считывать и из стандартного потока ввода. Её преимущество относительно gets в том, что она позволяет указать максимальный размер считываемой строки и заканчивает строку терминальным символом.

#include #include #include void main() { char buffer; //Считываем из стандартного потока ввода fgets(buffer, 127, stdin); printf("%s", buffer); //Этим можно заменить ожидание ввода символа scanf("1"); }

Это не полный набор различных функций символьного ввода и вывода. Таких функций море, но очень многие из них небезопасны, поэтому перед использованием внимательно читайте документацию.

Похожие публикации