книги / Программирование на языке Си
..pdf352 |
Программирование на языке Си |
ся во входном потоке. Если функция scanf() применяется для организации диалога с пользователем, то, будучи активизирова на повторно, она дочитает из входного потока "остатки" преды дущей порции данных, а не начнет анализ новой порции, введенной пользователем.
Предположим, что программа запрашивает у пользователя номер дома, в котором он живет. Программа обрабатывает код возврата функции scanf() в предположении, что во входных данных присутствует одно поле.
#±nclude <stdio.h> int main ()
{
int number;
printf("Введите номер дома: ") ; while (scanf("%d", (number) != 1)
printf("Ошибка. Введите номер дома: "); printf("Номер вашего дома %d\n", number); return 0;
}
При правильном вводе данных (введено целое десятичное число) результат будет следующий:
Введите номер дома: 25 ■Номер вашего дома 25
Предположим, что пользователь ошибся и ввел, например, следующую последовательность символов "@%". (Эти символы будут введены, если нажаты клавиши '2' и '5', но на верхнем ре гистре, т.е. одновременно была нажата клавиша <Shifit>.) В этом случае получится следующий результат:
Введите номер дома: 0% Ошибка. Введите номер дома: Ошибка. Введите номер дома:
Ошибочный символ @ прерывает работу функции scanf( )> но сам остается во входном потоке, и вновь делается попытка его преобразования при повторном вызове функции в теле цик ла while. Однако эта и последующие попытки ввода оказывают-
354 |
Программирование на языке Си |
fgets() - |
ввод (чтение) строки из файла; |
fputs() - запись строки в файл.
Различие между функциями fgetc(), getc() и fputc(), putc() здесь не рассматривается, и поэтому в примерах мы будем ис пользовать только одну из них.
Двоичный (бинарный) режим обмена с файлами. Двоич ный режим обмена организуется с помощью функций getc( ) и putc(), обращение к которым имеет следующий формат:
с = getc(fp); putc(c, fp);
где |
fp - указатель на поток; |
|
с - переменная типа int для приема очередного символа |
из файла или для записи ее значения в файл. |
|
Прототипы функции: |
|
int getc ( FILE *stream ); |
|
int |
putc ( int c, FILE *stream ); |
В качестве примера использования функций getc( ) и putc() рассмотрим программы ввода данных в файл с клавиатуры и программу вывода их на экран дисплея из файла.
Программа ввода читает символы с клавиатуры и записывает их в файл. Пусть признаком завершения ввода служит посту пивший от клавиатуры символ Имя файла запрашивается у пользователя. Если при вводе последовательности символов была нажата клавиша <Enter>, служащая разделителем строк при вводе с клавиатуры, то в файл записываются управляющие коды "Возврат каретки" (CR - значение 13) и "Перевод строки" (LF - значение 10). Код CR в дальнейшем при выводе вызывает перевод маркера (курсора) в начало строки экрана дисплея. Код LF служит для перевода маркера на новую строку дисплея. Зна чения этих кодов в тексте программы обозначены соответствен но идентификаторами CR и LF, т.е. CR и LF - именованные константы. Запись управляющих кодов CR и LF в файл позволя ет при последующем выводе файла на экран отделить строки друг от друга.
356 |
Программирование на языке Си |
/* Программа вывода символьного файла на экран дисплея */
♦include <stdio.h> int main ()
{
FILE *fp; /* Указатель на поток */ char с ;
char fname[20]; /* Массив для имени файла */
/* Запрос имени файла: */ puts("введите имя файла: \п "); gets(fname);
/* Открыть файл для чтения: */
if ((fp = fopen(fname,"r")) = = NULL)
{
perror(fname); return 1;
)
/* Цикл чтения из файла и вывода символов на экран: */
while ((с = getc(fp)) != EOF) putchar(c);
fclose(fp); /* Закрыть файл */ return 0;
>
Программу чтения символов из файла можно усовершенст вовать, добавив возможность вывода информации на экран пор циями (кадрами):
/* Усовершенствованная программа вывода символьного файла на экран дисплея по кадрам */
♦include <stdio.h> int main ()
{
FILE *fp; /* Указатель на поток) */ char с;
/* Восьмеричный код "Перевод строки": */ const char ЕЕ='\012';
int МАХ=10; /* Размер кадра */ int nline; /* Счетчик строк */
char fname[10]; /* Массив для имени файла */
Глава 7. Ввод и вывод |
357 |
/* Запрос имени файла: */ puts("введите имя файла \п"); gets(fname);
/* Открыть файл для чтения: */
if ((£р = fopen(fname,"г")) = = NULL)
{
perror(fname); return 1;
}
while (1)
{ /* Цикл вывода на экран */ nline = 1;
while (nline<MAX) /* Цикл вывода кадра */
{
с = getc(fp); if (с = EOF)
{
fclose(fp); return 0;
>
if (c == LF) nline++; putchar(c);
} /* Конец цикла вывода кадра*/ getchar(); /* Задержка вывода до
нажатия любой клавиши */ ) /* Конец цикла вывода */
} /* Конец программы */
В этой программе после вывода очередного кадра из МАХ строк для перехода к следующему кадру необходимо нажать любую клавишу.
Используя двоичный обмен с файлами, можно сохранять на диске информацию, которую нельзя непосредственно вывести на экран дисплея (целые и вещественные числа во внутреннем представлении).
Необходимые примеры и разъяснения приводятся в главе 8 при описании программы обслуживания базы данных о сотруд никах предприятия. Функции save() и load( ) из этого примера (см. §8.2) позволяют сохранить во внешней памяти и загрузить из внешней памяти базу данных о сотрудниках предприятия.
358 |
Программирование на языке Си |
Строковый обмен с файлами. Для работы с текстовыми файлами, кроме перечисленных выше, удобно использовать функции fgets() и fputs(). Прототипы этих функций в файле stdio.h имеют следующий вид:
int fputs(const char *s, FILE *stream); char * fgets(char *s, int n, FILE *stream);
Функция fputs() записывает ограниченную символом '\0' строку (на которую указывает s) в файл, определенный указате лем stream на поток, и возвращает неотрицательное целое. При ошибках функция возвращает EOF. Символ '\0' в файл не пере носится, и символ '\п' не записывается в конце строки вместо '\0'..
Функция fgets() читает из определенного указателем stream файла не более (п-1) символов и записывает их в строку, на ко торую указывает s. Функция прекращает чтение, как только про чтет (п-1) символов или встретит символ новой строки '\п', ко торый переносится в строку s. Дополнительно в конец каждой строки записывается признак окончания строки '\0'. В случае успешного завершения функция возвращает указатель s. При ошибке или при достижении конца файла, при условии, что из файла не прочитан ни один символ, возвращается значение NULL. В этом случае содержимое массива, который адресуется указателем s, остается без изменений. Напомним, что в отличие от fgets() функция gets() отбрасывает символ '\п'.
Проиллюстрируем возможности указанных функций на про грамме, которая переписывает текст из одного файла в другой. На этом же примере еще раз проиллюстрируем особенность языка Си - возможность передачи информации в выполняемую программу из командной строки (см. §5.8).
В стандарте языка Си определено, что любая программа на языке Си при запуске на выполнение получает от операционной системы информацию в виде значений двух аргументов - argc (сокращение от argument count - счетчик аргументов) и argv (сокращение от argument vector). Первый из них определяет ко личество строк, передаваемых-в виде массива указателей argv. По принятому соглашению argv[0] это всегда указатель на стро
360 |
Программирование на языке Си |
Обратите внимание, что значение argc явно не задается, а оп ределяется автоматически. Так как argv[0] определено всегда, то значение argc не может быть меньше 1. При отсутствии в ко мандной строке двух аргументов (имен файлов ввода-вывода) значение argc оказывается не равным трем, и поэтому на экран выводится поясняющее сообщение:
Формат вызова |
программы: |
файл-приемник |
copyfile.exe ' |
файл-источник |
Если имя входного файла указано неудачно или нет места на диске для создания выходного файла, то выдаются соответст вующие сообщения:
Ошибка при открытии файла f1.dat
или
Ошибка при открытии файла f 2 .txt
Режим форматного, обмена с файлами. В некоторых случа ях информацию удобно записывать в файл в виде, пригодном для непосредственного (без преобразования) отображения на экран дисплея, т.е. в символьном виде. Например, для сохране ния результатов работы программы, чтобы затем распечатать их на бумагу (получить "твердую" копию) или когда необходимо провести трассировку программы - вывести значения некото рых переменных во время выполнения программы для их по следующего анализа. В этом случае можно воспользоваться функциями форматного ввода (вывода) в файл fprintf() и fscanf(), которые имеют следующие прототипы:
int fprintf ( указатель напоток, форматная-строка, список-переменных)',
int fscanf ( указатель на поток, форматная строка, списокадресов переменных)',
Как и в функциях printf() и scanf(), форматная строка мо жет быть определена вне вызова функции1, а в качестве фактиче ского параметра в этом случае будет указатель на нее.