Разберем подробно структуру форматной строки. Эта строка включает в себя:
обычные символы, которые выводятся на экран в том же виде, в каком они указаны в форматной строке;
спецификаторы типа выводимого значения: %s, %d и %g;
спецсимвол перевода курсора на новую строку – \n.
Спецификаторы представляют собой «пустое место», куда должно быть вставлено значение аргумента соответствующего типа. Если спецификаторов несколько, то их порядок соответствует порядку, в котором перечисляются аргументы. Рассмотрим, какие спецификаторы вывода существуют в языке Си.
Тип данных
Спецификатор
Целое число со знаком
%d
Целое число без знака
%u
Символ
%c
Строка
%s
Вещественное число
%f
Вещественное число в экспоненциальной форме
%e или %E
Веществ. число без лишних нулей после запятой
%g или %G
Целое число в восьмеричной записи
%o
Целое число в шестнадцатеричной записи
%x или %X
Для лучшего понимания действий различных спецификаторов поэкспериментируйте с ними и со значениями разных типов.
В нашем примере также был использован спецсимвол \n. Рассмотрим на примере его работу. Предположим, что нам нужно поприветствовать двух людей, тогда разумно использовать следующий код:
printf("Hello, John!");
printf("Hello, Maria!");
Однако после запуска программы обнаружится, что оба приветствия появятся на одной строке:
Решение проблемы заключается в использовании специального символа \n,предназначенного для перевода курсора на новую строку. Добавление его в программу
printf("Hello, John!\n");
printf("Hello, Maria!");
приведет к желаемому выводу:
Специальные символы, такие как \n, не отображаемые при выводе, называются управляющими последовательностями; они управляют выводом, но сами на экран не выводятся, либо выводятся специальным образом. В следующей таблице перечислены спецсимволы языка Си.
Спецсимвол
Действие
\a
Звуковой сигнал (предупреждение)
\b
Возврат курсора на одну позицию
\n
Перевод курсора на новую строку
\r
Возврат курсора в начало строки
\t
Табуляция
\\
Вывод символа «\»
\'
Вывод символа «'»
\"
Вывод символа «"»
%%
Вывод символа «%»
Рассмотренный нами вид спецификаторов наподобие %d или %f является сокращенным. К спецификатору можно добавлять модификаторы вывода, которые изменяют способ вывода значений. Полный вид спецификатора следующий:
%[1][2].[4][5]
Здесь [1] – это модификатор, определяющий отображение выводимого значения; [2] – модификатор количества знаков, которое отводится под выводимое значение, [3] – количество знаков после запятой для вещественного числа, [4] – тип выводимого значения. Некоторые комбинации модификаторов невозможны.
Рассмотрим использование модификаторов на примерах. Начнем с модификатора количества знаков после запятой. Пока модификаторы [1] и [2] будут отсутствовать:
Обратите внимание на то, что число округляется, если количество знаком после запятой у него больше, чем отводится модификатором. Добавим теперь модификатор количества знаков, которое отводится под выводимое значение:
Здесь под все число отводится 10 знаков, и выводимое значение выравнивается по правому краю этой десятиместной ячейки. Модификатор «-» выравнивает значение по левому краю:
Существуют еще некоторые другие модификаторы, но они носят специфический характер, поэтому мы их рассматривать не станем. Желающие могут обратиться к документации по языку Си или другим учебникам.
Рассмотрим пример использования спецификаторов и модификаторов в комбинации с функцией sizeof() для вывода на экран размеров в байтах типов данных:
char frmt[] = "%-15s%5d\n";
printf("%-15s%5s\n", "Тип", "Размер");
printf("---------------------\n");
printf(frmt, "char", sizeof(char));
printf(frmt, "unsigned char",
sizeof(unsigned char));
printf(frmt, "short", sizeof(short));
printf(frmt, "unsigned short",
sizeof(unsigned short));
printf(frmt, "int", sizeof(int));
printf(frmt, "unsigned int",
sizeof(unsigned int));
printf(frmt, "float", sizeof(float));
printf(frmt, "double", sizeof(double));
printf(frmt, "bool", sizeof(bool));
printf(frmt, "void", sizeof(void));
printf("---------------------\n");
Ввод с клавиатуры и функция scanf()
Пришло время добавить в наши программы интерактивности: мы будем вводить информацию и заставлять компьютер выполнять действия, зависящие от введенной информации. Сущность ввода заключается в том, что отдельные символы или группы символов трактуются программой как целые числа, вещественные числа, символы или строки и сохраняются в указанные переменные. Причем, один и тот же набор символов в разных ситуациях может иметь разный тип. Скажем, набор символов 2014 может быть целым числом, может быть частью строки Сочи-2014 или четырьмя отдельными символами 2, 0, 1 и 4. Таким образом, наша задача определить то, как трактовать вводимые символы и указать переменные соответствующих типов, куда сохранить эти символы.
Наиболее общая функция, позволяющая вводить данные – это функция scanf(), она осуществляет форматный ввод. По аналогии с printf() она принимает форматную строку (шаблон) и список аргументов:
scanf("шаблон", список аргументов);
Важное отличие scanf() от printf() заключается в том, что в качестве аргументов функция scanf() принимает не имена переменных, а их адреса. Более подробно работа с адресами изучается в теме «Указатели», однако для работы с функцией scanf() не нужно глубоких знаний, связанных с указателями, а достаточно запомнить два простых правила:
если с помощью scanf() вводятся значения переменных, имеющих один из базовых типов, то перед именем переменной нужно поставить знак & (амперсанд);
если вводится строка и сохраняется в символьный массив, то амперсанд не требуется.
Самый простой способ использования функции scanf() – это ввод значения одной переменной. Следующий фрагмент кода демонстрирует, как ввести значения целочисленной переменной, вещественной, символьной и строковой:
//Ввод целого числа
int x;
scanf("%d", &x);
//Ввод вещественного числа
float y;
scanf("%f", &y);
//Ввод символа
int symbol;
scanf("%c", &symbol);
//Ввод строки
char str[100];
scanf("%s", str);
Рассмотрим теперь функцию scanf() более детально и исследуем ее возможности. Функция scanf() – это довольно мощный инструмент, который позволяет вводить одним нажатием клавиши «Enter» несколько переменных, причем, не обязательно одного типа. Данная функция использует служебные символы (пробелы, символы перевода строки и знаки табуляции) для разделения полей ввода. Например, если указан спецификатор вещественного числа %f, то функция берет из входного потока символы один за другим, пропуская все служебные символы. Поскольку указан спецификатор вещественного числа, то функция ожидает «плюс», «минус», цифры или знак «точка». Если она встречает другой символ, то возникает ошибка. Если ошибок нет, то символы читаются до первого служебного символа. Прочитанные символы преобразуются в вещественное число и сохраняются в указанную переменную. Если используется модификатор ширины поля, то чтение продолжается заданное количество символов. Аналогично вводятся и значения других типов. При вводе числа спецификатором %x допускаются буквы, используемые в шестнадцатеричной системе исчисления.
Разделять поля ввода можно и неслужебными символами. Например, шаблон "%f,%f,%f" говорит о том, что вводить числа нужно через запятую. Служебные символы игнорируются, поэтому данный шаблон, что и "%f, %f, %f". Вот примеры:
int n1, n2, n3;
printf("Введите три числа через пробел:\n");
scanf("%d %d %d", &n1, &n2, &n3);
Можно ввести значения через запятую:
float n1, n2, n3;
printf("Введите три числа через запятую:\n");
scanf("%f,%f,%f", &n1, &n2, &n3);
Обратите внимание, что сообщения для пользователя пишутся в функции printf(), а не в scanf().