Ввод и вывод в С
printf () является функцией стандартной библиотеки с переменным числом аргументов. Она всегда имеет по крайней мере один аргумент — строку формата, чаще всего строковый литерал. Строка может содержать спецификаторы преобразования. Функция сканирует строку и передает ее символы на стандартный вывод программы, по умолчанию консоль, пока не встретит спецификатор преобразования. В этом случае printf () ищет дополнительный аргумент, который форматируется и выводится в соответствии со спецификацией. Таким образом, вызов printf () должен содержать столько дополнительных аргументов, сколько спецификаторов преобразования имеется в строке формата.
Спецификация преобразования
Синтаксис спецификатора преобразования имеет такой вид:
%[флаги] [поле][.точность][размер]символ типа
Как видите, обязательными элементами спецификатора являются только начальный знак процента и символ, задающий тип преобразования. Следующая таблица перечисляет возможные варианты различных элементов спецификации.
Таблица 3.4. Элементы спецификатора преобразования
Элемент |
Символ |
Аргумент |
Описание |
||||
флаг | - | Выровнять вывод по левому краю поля. | |||||
0 | Заполнить свободные позиции нулями вместо пробелов. | ||||||
+ | Всегда выводить знак числа. | ||||||
пробел | Вывести пробел на месте знака, если число положительное. | ||||||
# | Вывести 0 перед восьмеричным или Ох перед шестнадцатеричным значением. | ||||||
поле | число | Минимальная ширина поля вывода. | |||||
точность | число | Для строк — максимальное число выводимых символов; для целых — минимальное число выводимых цифр; для вещественных — число цифр дробной части. | |||||
размер | h | Аргумент -- короткое целое. | |||||
1 | Аргумент — длинное целое. | ||||||
L | Аргумент имеет тип long double. | ||||||
Элемент |
Символ |
Аргумент |
Описание |
||||
символ типа | d | целое | Форматировать как десятичное целое со знаком. | ||||
i | целое | То же, что и d. | |||||
о | целое | Форматировать как восьмеричное без знака. | |||||
U | целое | Форматировать как десятичное без знака. | |||||
х | целое | Форматировать как шестнадцатеричное в нижнем регистре. | |||||
Х | целое | Форматировать как шестнадцатеричное в верхнем регистре. | |||||
f | вещественное | Вещественное в форме [-]dddd.dddd. | |||||
е | вещественное | Вещественное в форме [-]d.dddde[+|-]dd. | |||||
Е | вещественное | То же, что и е, с заменой е на Е. | |||||
ё | вещественное | Использовать форму f или е в зависимости от величины числа и ширины поля. | |||||
G | вещественное | То же, что и g — но форма f или Е. | |||||
с, | символ | Вывести одиночный символ. | |||||
s | строка | Вывести строку. | |||||
п | указатель | Аргумент — указатель на переменную типа int. В нее записывается количество выведенных к данному моменту символов. | |||||
р | указатель | Вывести указатель в виде шестнадцатеричного числа ХХХХХХХХ. |
Как видите, флаги задают “стиль” представления чисел на выводе, поле и точность определяют характеристики поля, отведенного под вывод аргумента, размер уточняет тип аргумента и символ_типа задает собственно тип преобразования. Следующий пример показывает возможности форматирования функции printf () . Советую не полениться и поэкспериментировать с этим кодом, меняя флаги и параметры поля вывода.
Листинг 3.1. Возможности функции printf ()
/*
** Printf.с: Демонстрация форматирования вывода на консоль
** функцией printf().
* /
#pragma hdrstop
#include <stdio.h>
#include <conio.h>
#pragma argsused
int main(int argc, char *argv[])
{
double p = 27182.81828;
int j = 255;
char s[] = "Press any key...";
/* Вывести 4 цифры; вывести обязательный знак: */
printf("Test integer formatting: %13.4d %4-8d\n", j, j);
/* Вывести по левому краю со знаком; заполнить нулями: */ printf("More integer formatting: %-+13d % 08d\n", j, j);
printf("Test octal and hex: %#13o %#8.6x\n", j, j);
printf("\nTest e and f conversion: %13.7e %8.2f\n", p, p) ;
printf("\n%s", s); /* Вывести строку подсказки. */
getch () ;
return 0;
}

Рис. 3.1 Тестирование функции printf()

Прием, позволяющий компилировать программу с главным файлом .с (а не .срр), описан в предыдущей главе в замечании к разделу о консольных приложениях. Конечно, показанная программа будет компилироваться и в режиме C++.
Escape-последовательности
В строках языка С для представления специальных (например, непечатаемых) символов используются escape-последователъности, состоящие из обратной дробной черты, за которой следует один или несколько символов. (Название появилось по аналогии с командами управления терминалом или принтером, которые действительно представляли собой последовательности переменной длины, начинающиеся с кода ESC.) В приведенных примерах функции printf () вы уже встречались с одной такой последовательностью — \n. Сама обратная косая черта называется escape-символом..
В таблице 3.5 перечислены возможные esc-последовательности.
Таблица 3.5. Escape-последовательности языка С
Последовательность |
Название |
Описание |
\а | Звонок | Подает звуковой сигнал. |
\b | Возврат на шаг | Возврат курсора на одну позицию назад. |
\f | Перевод страницы | Начинает новую страницу. |
\n | Перевод строки | Начинает новую строку. |
\r | Возврат каретки | Возврат курсора к началу текущей строки. |
\t | Табуляция | Переход к следующей позиции табуляции. |
\v | Вертикальная табуляция | Переход на несколько строк вниз. |
\\ | Выводит обратную дробную черту. | |
\' | Выводит апостроф (одинарную кавычку). | |
\" | Выводит кавычку (двойную). |
\000 | От одной до трех восьмеричных цифр после esc-символа. |
\хНН или \ХНН | Одна или две шестнадцатеричных цифры после esc-символа. |
В языке С для ввода имеется “зеркальный двойник” printf() — функция scant (). Функция читает данные со стандартного ввода, по умолчанию — клавиатуры. Она так же, как и printf () , принимает строку формата с несколькими спецификаторами преобразования и несколько дополнительных параметров, которые должны быть адресами переменных, куда будут записаны введенные значения.

В языке С функция не может изменять значение передаваемых ей аргументов, поскольку ей передается только временная копия содержимого соответствующей переменной. Это называется передачей параметра.по значению. В языке Pascal возможна также передача по ссылке, позволяющая функции изменить саму переменную-аргумент. Параметр, передаваемый по ссылке, объявляется с ключевым словом var. В С нет автоматического механизма передачи по ссылке. Чтобы передать из функции некоторое значение через параметр, ее вызывают с указателем на переменную (грубо говоря, ее адресом), подлежащую модификации. Функция не может изменить переданный ей аргумент, т. е. сам адрес, но она может записать информацию в память по этому адресу. Адрес получают с помощью операции &, например, SaVar. Подробнее мы обсудим это, когда будем говорить об указателях.
Примером вызова scanf () может служить следующий фрагмент кода:
int age;
printf("Enter your age: "); //' Запросить ввод возраста
// пользователя. scanf ("%d", &age); // Прочитать введенное число.
Функция возвращает число успешно сканированных полей, которое в приведенном фрагменте игнорируется. При необходимости вы можете найти полную информацию по scanf () в оперативной справке C++Builder. Однако следует сказать, что программисты не любят эту функцию и пользуются ей очень редко. Причина в том, что опечатка при вводе (скажем, наличие буквы в поле, предполагающем ввод числа и т. п.) может привести к непредсказуемым результатам. Контролировать корректность ввода и обеспечить адекватную реакцию программы на ошибку при работе со scanf () довольно сложно. Поэтому часто предпочитают прочитать целиком всю строку, введенную пользователем, в некоторый буфер, а затем самостоятельно декодировать ее, выделяя отдельные лексемы и преобразуя их в соответствующие значения. В этом случае можно контролировать каждый отдельный шаг процесса преобразования.
Ввод строки с клавиатуры производится функцией gets ():
char s[80] ;
gets (s) ;

gets(&s[0]);
// Аргумент - указатель на начальный элемент
// массива s.
Для преобразования строк, содержащих цифровое представление чисел, в численные типы данных могут применяться функции atoi(), ato1 () и atof (). Они преобразуют строки соответственно в целые, длинные целые и вещественные числа (типы int, long и double). Входная строка может содержать начальные пробелы; первый встреченный символ, который не может входить в число, завершает преобразование. Прототипы этих функций находятся в файле stdlib.h.