Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Программирование на языке Си

..pdf
Скачиваний:
15
Добавлен:
12.11.2023
Размер:
17.16 Mб
Скачать

332

Программирование на языке Си

Функция getchar( ) осуществляет ввод одного символа. При обращении она возвращает в вызвавшую ее функцию один вве­ денный символ.

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

Обратите внимание на то, что функция getchar() вводит оче­ редной байт информации (символ) в виде значения типа int. Это сделано для того, чтобы гарантировать успешность распознава­ ния ситуации "достигнут конец файла". Дело в том, что при чтении из файла с помощью функции getchar() может быть достигнут конец файла. В этом случае операционная система в ответ на попытку чтения символа передает функции getchar() значение EOF (End of File). Константа EOF определена в заго­ ловочном файле stdio.h и в разных операционных системах имеет значение 0 или -1. Таким образом, функция getchar() должна иметь возможность прочитать из входного потока не только символ, но и целое значение. Именно с этой целью функция getchar() всегда возвращает значение типа int.

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

В случае ошибки при вводе функция getchar() также воз­ вращает EOF.

Строго говоря, функции getchar() и putchar() функциями не являются, а представляют собой макросы, определенные в заго­ ловочном файле stdio.h следующим образом:

#define

getcharО

getc(stdin)

#define

putchar(c)

putc ((c), stdout)

Здесь переменная с определена как int с.

Функции getc() и putc( ), с помощью которых определены функции getchar( ) и putchar(), имеют следующие прототипы;

int getc (FILE

‘ stream);

int putc (int c,

FILE ‘ stream);

Глава 7. Ввод и вывод

333

Указатели на поток, задаваемые в этих функциях в качестве параметра, при определении макросов getchar() и putchar() имеют соответственно предопределенные значения stdin (стан­ дартный ввод) и stdout (стандартный вывод).

Интересно отметить, что функции getc() и putc(), в свою очередь, также реализуются как макросы. Соответствующие строки легко найти в заголовочном файле stdio.h.

Не разбирая подробно эти макросы, заметим, что вызов биб­ лиотечной функции getc( ) приводит к чтению очередного байта информации из стандартного ввода с помощью системной функции (ее имя зависит от операционной системы) лишь в том случае, если буфер операционной системы окажется пустым. Если буфер не пуст, то в программу пользователя будет передан очередной символ из буфера. Это необходимо учитывать при работе с программой, которая использует функцию getchar() для ввода символов.

При наборе текста на клавиатуре коды символов записыва­ ются во внутренний буфер операционной системы, Одновре­ менно они отображаются (для визуального контроля) на экране дисплея. Набранные на клавиатуре символы можно редактиро­ вать (удалять и набирать новые). Фактический перенос симво­ лов из внутреннего буфера в программу происходит при нажа­ тии клавиши <Enter>. При этом код клавиши <Enter> также за­ носится во внутренний буфер. Таким образом, при нажатии на клавишу 'А' и клавишу <Enter> (завершение ввода) во внутрен­ нем буфере оказываются: код символа 'А' и код клавиши <Enter>.

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

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

#±nclude <stdio.h> int main ()

{

printf("a");

334

 

 

Программирование на языке Си

getchar();

/*

#1

*/

printf("b");

/*

#2

*/

getcharO ;

printf("c");

 

 

 

return 0;

 

 

 

Сначала на экран выводится символ 'а', и работа программы приостанавливается до ввода очередного (в данном случае - любого) символа. Если, как это делается обычно, нажать, на­ пример, клавишу <q> и затем клавишу <Enter> (для завершения ввода), то на следующей строке появятся символы Ьс, и про­ грамма завершит свою работу. Первая (в программе) функция getchar() (#1) прочитала из внутреннего буфера код символа 'q', и следующая за ней функция printf( ) вывела на экран символ Ъ'. Остановки работы программы не произошло, потому что вторая функция getchar() (#2) прочитала код клавиши <Enter> из внутреннего буфера, а не очередной символ с клавиатуры. Произошло это потому, что к моменту вызова функции getchar( ) внутренний буфер не был пуст.

Приведенная программа будет работать правильно, если в момент остановки программы нажимать только клавишу <Enter>.

Функция putchar() служит для вывода на устройство стан­ дартного вывода одного символа, заданного в качестве парамет­ ра. Ниже приведены примеры задания выводимого символа:

int с;

1с = getchar( );

2putchar(c);

3 putchar('А');

4putchar('\007');

5putchar('\t');

Встроке 2 фрагмента программы на экран дисплея выводит­ ся символ, введенный в предыдущей строке функцией getchar( ). В строке 3 выводится символ 'А', в строке 4 выводит­

ся управляющий символ, заданный кодом 007 (звуковой сиг­ нал). В последней строке выводится неотображаемый (управ-

Глава 7. Ввод и вывод

335

ляющий) символ табуляции, перемещающий курсор в следую­ щую позицию табуляции. Обычно эти позиции задаются сле­ дующим числовым рядом: 1,9,17,25...

Приведем в качестве примера применения функций getchar() и putchar() программу копирования данных из стан­ дартного ввода в стандартный вывод, которую можно найти практически в любом пособии по программированию на Си:

#include <stdio.h> int main()

{

int c;

while ((c = getchar()) != EOF) putchar(c) ;

return 0;

}

Эта же программа с использованием функций getc() и putc() будет выглядеть так:

♦include <stdio.h> int main ()

{

int с ;

while ((с = getc(stdin)) != EOF) putc(c, stdout);

return 0;

}

Для завершения приведенной выше программы копирования необходимо ввести с клавиатуры сигнал прерывания Ctrl+C (одновременно нажать клавиши <Ctrl> и <С>).

В [1, §1.5] приведены примеры использования функций getchar() и putchar() для подсчета во входном потоке числа отдельных введенных символов, строк и слов.

Ввод-вывод строк. Одной из наиболее популярных опера­ ций ввода-вывода является операция ввода-вывода строки сим­ волов. В библиотеку языка Си для обмена данными через стандартные потоки ввода-вывода включены функции вводавывода строк gets() и puts(),' которые удобно использовать при

336

Программирование на языке Си

создании диалоговых систем. Прототипы этих функций имеют следующий вид:

char * gets (char * s);

/* Функция ввода *1

int puts (char * s);

/* Функция вывода */

Обе функции имеют только один аргумент - указатель s на массив символов. Если строка прочитана удачно, функция gets( ) возвращает адрес того массива s, в который производился ввод строки. Если произошла ошибка, то возвращается NULL.

Функция puts() в случае успешного завершения возвращает последний выведенный символ, который всегда является сим­ волом V . Если произошла ошибка, то возвращается EOF.

Приведем простейший пример использования этих функций.

# i n c l u d e < s t d i o . h >

c h a r

s t r l [ ] = " В в е д и т е ф амилию с о т р у д н и к а : " ;

i n t

m a in ()

{

char name[80]; puts(strl); gets(name); return 0;

}

Напомним, что любая строка символов в языке Си должна заканчиваться нуль-символом 'W. В последний элемент массива strl нуль-символ будет записан автоматически во время транс­ ляции при инициализации массива. Для функции puts() нали­ чие нуль-символа в конце строки является обязательным. В противном случае, т.е. при отсутствии в символьном массиве символа 'W, программа может завершиться аварийно, так как функция puts() в поисках нуль-символа будет перебирать всю доступную память байт за байтом, начиная в нашем примере с адреса strl. Об этом необходимо помнить, если в программе происходит формирование строки для вывода ее на экран дис­ плея. Функция gets( ) завершает свою работу при вводе символа 'Vn', .который автоматически передается от клавиатуры в ЭВМ при нажатии на клавишу <Enter>. При этом сам символ '\п' во

Ввод и вывод

337

вводимую строку не записывается. Вместо него в строку поме­ щается нуль-символ '\0'. Таким образом, функция gets() произ­ водит ввод "правильной" строки, а не просто последователь­ ности символов.

Здесь следует обратить внимание на следующую особен­ ность ввода данных с клавиатуры. Функция gets() начинает об­ работку информации от клавиатуры только после нажатия клавиши <Enter>. Таким образом, она "ожидает", пока не будет набрана нужная информация и нажата клавиша <Enter>. Только после этого начинается ввод данных в программу.

Форматный ввод-вывод. В состав стандартной библиотеки языка Си включены функции форматного ввода-вывода. Ис­ пользование таких функций позволяет создавать программы, способные обрабатывать данные в заданном формате, а также осуществлять элементарный синтаксический анализ вводимой информации уже на этапе ее чтения. Функции форматного вво­ да-вывода предназначены для ввода-вывода отдельных симво­ лов, строк, целых восьмеричных, шестнадцатеричных, десятичных чисел и вещественных чисел всех типов.

Для работы со стандартными потоками в режиме форматного ввода-вывода определены две функции:

printf() - форматный вывод; scanf() - форматный ввод.

Форматный вывод в стандартный выходной поток. Про­ тотип функции printf( ) имеет вид:

int printf(const char *format,...);

При обращении к функции printf() возможны две формы за­ дания первого параметра:

int printf ( форматная строка, список аргументов)', int printf ( указатель на форматную строку,

списокаргументов)',

В обоих случаях функция printfQ преобразует данные из внутреннего представления в символьный вид в соответствии с

2 2 “3124

338

Программирование на языке Си

форматной строкой и выводит их в выходной поток. Данные, которые преобразуются и выводятся, задаются как аргументы функции printf().

Возвращаемое значение функции printf() - число напеча­ танных символов; а в случае ошибки - отрицательное число.

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

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

спецификация преобразования.

Если аргументов недостаточно для данной форматной стро­ ки, то результат зависит от реализации (от операционной систе­ мы и от системы программирования). Если аргументов больше, чем указано в форматной строке, "лишние" аргументы игнори­ руются. Гарантируется, что при любом количестве параметров и любом их типе после выполнения функции printf() дальнейшее выполнение программы будет корректным.

Списокаргументов (с предшествующей запятой) может от­ сутствовать,

Спецификация преобразования имеет следующую форму:

% флаги ширина_поля.точностъ модификатор спецификатор

. Символ % является признаком спецификации преобразова­ ния. В спецификации преобразования обязательными являются только два элемента: признак % и спецификатор.

Глава 7. Ввод и вывод

339

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

Предупреждение. Спецификации преобразований должны соответствовать типу указанных аргументов. При несовпаде­ нии не будет выдано сообщений об ошибках во время ком­ пиляции или выполнения программы, но в выводе результатов выполнения программы может содержаться "мусор".

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

Таблица 7 . 1

Спецификаторы форматной строки для функции форматного вывода

Спе­ Тип цифи­ аргумента катор

dint, char, unsigned

1int, char, unsigned

Uint, char, unsigned

Оint, char, unsigned

Xint, char, unsigned

Xint, char, unsigned

гdouble,- float

Формат вывода

Десятичное целое со знаком

Десятичное целое со знаком

Десятичное целое без знака

Восьмеричное целое без знака

Шестнадцатеричное целое без знака; при выводе ис­ пользуются символы "0...9а...Г Шестнадцатеричное целое без знака; при выводе ис­ пользуются символы "0...9A...F

Вещественное значение со знаком в виде:

3 H a K _ u u c a a d d d d .d d d d ,

где dddd - одна йли более десятичных цифр. Количе­ ство цифр перед десятичной точкой зависит от вели­ чины выводимого числа, а количество цифр после десятичной точки зависит от требуемой точности. З н а к _ ч и с л а при отсутствии модификатора '+' изобра­ жается только для отрицательного числа

22’

340

Программирование на языке Си

 

 

П р о д о л ж е н и е

Спе­

Тип

Формат вывода

цифи­

аргумента

 

катор

 

 

е

double,

Вещественное значение в виде:

 

float

знакчнслат.ббббезнакххх,

 

 

где m.dddd - изображение мантиссы числа;

 

 

m - одна десятичная цифра;

 

 

dddd - последовательность десятичных цифр;

 

 

е - признак порядка;

 

 

з н а к - знак порядка;

 

 

ххх - десятичные цифры для представления поряд­

 

 

ка числа;

 

 

з н а к ч и с л а при отсутствии модификатора '+' изо­

 

 

бражается только для отрицательного числа

Еdouble, Идентичен спецификатору "е", за исключением того,

float

gdouble, float

что признаком порядка служит "Е"

Вещественное значение со знаком печатается в форма­ те спецификаторов "Г или "е" в зависимости от того, какой из них более компактен для данного значения и точности. Формат спецификатора "е" используется то-

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

G

double,

Идентичен формату спецификатора "g", за исключени­

 

float

ем того, что признаком порядка служит "Е"

Сint, char, Одиночный символ unsigned

S

char *

Символьная строка. Символы печатаются либо до пер­

 

 

вого нулевого символа ('\0') или печатается то количе­

 

 

ство символов, которое задано в поле т о ч н о с т ь спе­

 

 

цификации преобразования

рvoid * Значение адреса. Печатает адрес, указанный аргумен­

том (представление адреса зависит от реализации)

Приведем примеры использования различных спецификато­ ров. В каждой строке вызова функции printf() в качестве ком­ ментариев приведены результаты выбода. Переменная code

Глава 7. Ввод и вывод

341

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

#±nclude <stdio.h> int main()

{

int number = 27;

 

 

float

f =

123.456;

 

 

char

str[4] =

"abc";

 

 

char

c =

'a ';.

 

 

int code;

 

 

 

 

printf("%d\n",

number);

/*

27

printf("%o\n", number);

/*

33

printf("%x\n", number);

/*

lb

code

= printf("%f\n", f);

/*

123.456001

printf("code =

%d\n", code);

/*

code = 11

printf("%e\n",

f);

/*

1.23456e+02

printf("%c\n", c);

/*

a

printf("%s\n", str);

/*

abc

return 0;

 

 

 

 

}

V

*/

V

V

*/

V

V

*/

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

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

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

+Если выводимое значение имеет знак (любой: '+'

 

или

то он выводится. Без этого флага знак

 

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

пробел

Используется для вставки пробела на месте знака

 

перед положительными числами.

Соседние файлы в папке книги