Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
BOOK_С_INTUIT.doc
Скачиваний:
4
Добавлен:
19.09.2019
Размер:
7.91 Mб
Скачать

Контрольные вопросы

  1. Каким образом можно вернуть из функции несколько значений?

  2. Каким образом определяется тип функции?

  3. Как выглядит описание функции, которая возвращает указатель на заданный тип, например char?

  4. Можно ли использовать многоуровневую адресацию для функции, которая возвращает указатель на заданный тип? Если можно, то как происходит определение такой функции?

  5. В каком месте программы можно определить указатель на функцию?

  6. Имеет ли указатель на функцию прототип и определение?

  7. Как осуществляется вызов функции с помощью указателя?

  8. Как взаимосвязаны между собой объявление функции, ее определение и вызов?

Библиографический список

  1. Керниган Б. У. Язык программирования С : пер. с англ./Б. У.Керниган, Д.  М.Ритчи. – 2-е изд. – М.: Вильямс, 2007. – 304 с.

  2. Дейтл Х.М. Как программировать на С : пер. с англ./Х.М. Дейтл, П.Дж. Дейтл. – 4-е изд. – М. : Бином-Пресс, 2006. – 912 с.

  3. Фридман А. С/С++. Архив программ / А. Фридман, Л. Кландер, М. Михаэлис, Х. Шильдт. – М. : БИНОМ, 2001. – 640 с.

Тема 12 Файловый ввод/вывод в языке с

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

ТЕОРЕТИЧЕСКАЯ ЧАСТЬ

Файл – это именованный объект, хранящий данные (программу или любую другую информацию) на каком-либо носителе (дискете, винчестере, CD) [1].

В языке С файлом может быть все, начиная с дискового файла и заканчивая терминалом или принтером [2]. Поток связывают с определенным файлом, выполняя операцию открытия, после которой можно проводить обмен информацией между файлом и программой. Не у всех файлов одинаковые возможности. Например, к дисковому файлу прямой доступ возможен, в то время как к некоторым принтерам – нет. В языке С все потоки одинаковы, а файлы – нет [2].

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

Файл отсоединяется от определенного потока (т.е. между файлом и потоком разрывается связь) с помощью операции закрытия. При закрытии файла, открытого с целью вывода, содержимое (если оно есть) связанного с ним потока записывается на внешнее устройство. Этот процесс, который обычно называют дозаписью потока, гарантирует, что никакая информация случайно не останется в буфере диска. Если программа завершает работу нормально, т.е. либо функция main() возвращает управление операционной системе, либо вызывается функция exit(), то все файлы закрываются автоматически. В случае аварийного завершения программы, например краха или вызова функции abort(), файлы не закрываются [2].

Файловая система языка С предназначена для работы с самыми разнообразными устройствами, в том числе с терминалами, дисками и накопителями на магнитной ленте. Даже если какое-то из них сильно отличается от других, буферизованная файловая система все равно представит его в виде логического устройства, которое называется потоком. Потоки бывают двух видов: текстовые и двоичные [2].

Текстовый поток – это последовательность символов. В стандарте С считается, что текстовый поток организован в виде строк, каждая из которых заканчивается символом новой строки. Однако в конце последней строки этот символ не обязателен. В текстовом потоке по требованию базовой среды могут происходить преобразования символов. Например, символ новой строки может быть заменен парой символов – возврата каретки (например, \r) и перевода строки (например, \n), т.е. \r\n.

Двоичные потоки – это последовательность байтов, которая взаимно однозначно соответствует байтам на внешнем устройстве, причем никакого преобразования символов не происходит [2]. Кроме того, количество тех байтов, которые пишутся (читаются), и тех, которые хранятся на внешнем устройстве, одинаково. Однако в конце двоичного потока может добавляться определяемое приложением количество нулевых байтов. Они могут использоваться, например, для заполнения свободного места в блоке памяти незначащей информацией, чтобы она полностью заняла сектор на диске.

Файловая система языка С состоит из нескольких взаимосвязанных функций [2]. Самые распространенные из них показаны в табл.12.1.

Таблица 12.1

Функции файловой системы языка С

№ п/п

Имя функции

Действие функции

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

fopen()

fclose()

putc()

fputc()

getc()

fgetc()

fgets()

fputs()

fseek()

ftell()

fprintf()

fscanf()

feof()

ferror()

rewind()

remove()

fflush()

Открывает файл

Закрывает файл

Записывает символ в файл

То же, что putc()

Читает символ из файла

То же, что getc()

Читает строку из файла

Записывает строку в файл

Устанавливает указатель текущей позиции на определенный байт файла

Возвращает текущее значение указателя текущей позиции в файле

Для файла то же, что printf() для консоли

Для файла то же, что scanf() для консоли

Возвращает значение true (истина), если достигнут конец файла

Возвращает значение true (истина), если произошла ошибка

Устанавливает указатель текущей позиции в начало файла

Стирает файл

Производят дозапись потока в файл

Для приведенных функций требуется подключить заголовок <stdio.h>. Запись или чтение из файла осуществляются с помощью указателя. Указатель файла – это указатель на структуру типа FILE. Для объявления переменной–указателя файла, например *fp, используется оператор

FILE *fp;

Идентификатор FILE представляет собой своеобразный тип данных, а указатель *fp содержит адрес объекта этого типа.

Указатель файла указывает на структуру, содержащую различные сведения о файле, его имени, статусе и указателе текущей позиции в начало файла [2].

Открытие файла осуществляется с помощью функции fopen() (fopen_s()в Visual Studio 2010), которая открывает поток и связывает с ним определенный файл. Прототип функции fopen() такой:

FILE *fopen(const char *file_name, const char *mode);

Здесь формальные переменные имеют следующий смысл: file_name – это имя файла с заданным расширением и возможным путем расположения, mode – режим работы файла: чтение, запись и т.д. [1]. В табл.12.2 [2], приводятся допустимые значения режимов для функции fopen().

Таблица 12.2

Допустимые значения режимов функции fopen()

№ п/п

Режим

Значение режима

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

r

w

a

rb

wb

ab

r+

w+

a+

r+b

w+b

a+b

Открыть текстовый файл для чтения

Создать текстовый файл для записи

Добавить в конец текстового файла

Открыть двоичный файл для чтения

Создать двоичный файл для записи

Добавить в конец двоичного файла

Открыть текстовый файл для чтения/записи

Создать текстовый файл для чтения/записи

Добавить в конец текстового файла или создать текстовый файл для чтения/записи

Открыть двоичный файл для чтения/записи

Создать двоичный файл для чтения/записи

Добавить в конец двоичного файла или создать двоичный файл для чтения/записи

Например, для записи в файл с именем (и расширением) data.txt на диск D следует использовать такие объявление и операции:

FILE *fp;

fp = fopen("D: \\data.txt", "w");

fprintf(fp, "\n\t hello, world\n");

fclose(fp);

В приведенном фрагменте С-кода функция fclose() закрывает поток, который был открыт с помощью вызова функции fopen(). Функция fprintf() осуществляет форматную запись (в данном случае строку hello, world) в файл. Все манипуляции с файлом происходят между функциями fopen() и fclose(). Режим функции fopen() задается строкой "w", которая обеспечивает создание текстового файла для записи. Это означает, что файл data.txt создается на диске D и в него записывается строка hello, world с отступом от верхнего и левого краев.

Прототип функции fclose() следующий:

int fclose(FILE *fp);

Здесь *fp – указатель файла, возвращенный в результате вызова функции fopen()[2]. Возвращение нуля означает успешную операцию закрытия. В случае ошибки возвращается EOF. Обычно отказ при выполнении функции fclose() наблюдается только тогда, когда диск был преждевременно удален из дисковода или на нем не осталось свободного места.

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

FILE *fp;

if ((fp = fopen("D:\\data.txt", "w")) == NULL) {

//exit(1);

printf("\n\t Error! Can not open file\n ");

printf("\n Press any key: ");

_getch(); return -1; }

fprintf(fp, "\n\t hello, world\n");

fclose(fp);

При выполнении условия проверки можно выходить из программы, нажав любую клавишу с заданным сообщением или обратившись к функции exit(), которая в данном фрагменте С-кода закомментирована. В Microsoft Visual Studio 2010 (а также в 2008) рекомендуется применять fopen_s() вместо функции fopen().

Функции, работающие с текстовыми файлами, удобно использовать при создании таких файлов, ведении файлов-протоколов и т.п., а при организации баз данных целесообразно применять функции для работы с бинарными файлами: fwrite() и fread(). Они без каких-либо изменений копируют выделенный блок данных из оперативной памяти в файл и, наоборот [1]. При записи или чтении суффикс "t" (например, "wt") открывает файл в текстовом режиме. Тогда CTRL+Z (символ с кодом 26) обрабатывается как символ конца файла. Кроме того, комбинации символов перевода строки и возврата каретки преобразуются  в единственный символ перевода строки ('\n') при вводе, и символы перевода строки – в комбинации символов перевода строки и возврата каретки при выводе. Суффикс "b" открывает файл в бинарном режиме, преобразования символов перевода строки и возврата каретки не производятся.

ПРАКТИЧЕСКАЯ ЧАСТЬ

Пример1. Написать программу заполнения матрицы размера n×m нечетными целыми числами с выводом результата на консоль и в текстовый файл. Размеры матрицы и начальное нечетное число задаются пользователем с клавиатуры.

Программный код решения примера

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

int main(void) {

int i, j, x, xi, n, m, *matr;

FILE *fid;

char str[] = "D:\\data.txt"; // месторасположение файла

if ((fid = fopen(str, "w")) == NULL) {

printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: ");

_getch(); return -1; }

printf("\n\t Enter the number of lines: "); scanf_s("%d", &n);

printf("\t Enter the number of columns: "); scanf_s("%d", &m);

printf("\t Enter the odd number: "); scanf_s("%d", &x);

xi = x;

matr = (int *)calloc(n*m, sizeof(int));

// Заполнение матрицы целыми числами

for (i = 0; i < n; ++i)

for (j = 0; j < m; ++j)

{matr[i*m + j] = x; x += 2; }

printf("\n\t Matrix (%d x %d), initial number: %d\n",n,m,xi);

fprintf(fid, "\r\n\t Matrix (%d x %d), initial number: %d\r\n", n, m, xi);

for (i = 0; i < n; ++i) {

printf("\n "); fprintf(fid, "\r\n ");

for (j = 0; j < m; ++j) {

printf("%5d", matr[i*m + j]);

fprintf(fid, "%5d", matr[i*m + j]);

}

}

fclose(fid);

printf("\n\n Result of record look in file %s\n", str);

printf("\n Press any key: ");

_getch();

return 0;

}

В программу включена препроцессорная директива #define для устранения предупреждения о ненадежной работе функции fopen() в Visual Studio 2010.

В озможный результат выполнения программы показан на рис.12.1.

Рис.12.1. Заполнение матрицы нечетными числами

Т екстовый файл с заполненной матрицей представлен на рис.12.2.

Рис.12.2. Матрица нечетных чисел в текстовом файле

Примечание. В текстовом файле следует использовать моноширинный (равноширинный) шрифт, например Courier New.

Задание1

  1. Вместо функции calloc() примените функцию malloc().

  2. Найдите сумму элементов столбцов матрицы. Результат запишите под матрицей.

  3. Произведите заполнение матрицы нечетными числами по столбцам.

  4. Запишите сформированную матрицу в файл с расширениями .doc, .xls, .rtf, .csv. Просмотрите полученные файлы.

  1. Сформируйте матрицу из четных чисел размером (3Х)×(4Х), результат выведите в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

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

В качестве строки возьмем «hello, world». Для посимвольной записи в файл используем функции putc() и fputc(), которые реализованы для сохранения совместимости со старыми версиями языка С. Для прекращения чтения символов с клавиатуры используем точку '.'.

Программный код решения примера

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <conio.h>

int main(void) {

char ch; FILE *f_in, *f_out;

char str[] = "D:\\data.txt"; // файл записи

char str2[] = "D:\\data2.txt";// файл перезаписи

if ((f_in = fopen(str, "w")) == NULL) {

printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: ");

_getch(); return -1;

}

printf("\n Enter the characters by pressing Enter and exit point:\n\n> ");

while ((ch = getchar()) != '.')

{ printf(" "); fputc(ch, f_in);}

fclose(f_in);

if ((f_in = fopen(str, "r")) == NULL){

printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: ");

_getch(); return -1; }

if ((f_out = fopen(str2, "w")) == NULL){

printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: ");

_getch(); return -1;}

while( (ch = getc(f_in)) != EOF )

putc(ch, f_out);

fclose(f_in);

fclose(f_out);

printf("\n\n Result of record look in file %s\n", str);

printf(" Result of rewriting look in file %s\n", str2);

printf("\n Press any key: ");

_getch();

return 0;

}

В программе сначала открывается файл data.txt для записи в него символов, затем он закрывается. Этот же файл необходим для считывания записанных символов с целью записи их в другой файл под именем data2.txt. Всякий раз производится проверка возможности открытия файлов. Запись символов в текстовый файл выполняется с помощью функций putc() и fputc(), считывание символов из файла – с помощью функции getc().

В среде Visual Studio стандартная функция fopen() языка С вызывает предупреждение при компиляции программы. Для его устранения в программу включена препроцессорная директива

#define_CRT_SECURE_NO_WARNINGS

Р езультат выполнения программы показан на рис.12.3.

Рис.12.3. Консольный ввод символов для записи в файл

Задание2

  1. Проверьте функцию fgetc() для чтения символов из файла.

  2. Посимвольную запись в текстовый файл строки «hello, world» осуществите с предварительной инициализацией соответствующего символьного массива.

  3. Программу выполните для записи фамилии пользователя в текстовые файлы и с помощью функций fopen_s().

  4. Подготовьте текстовый файл со своими фамилией, именем, номером группы и специальности. Выполните чтение символов из этого файла с выводом на консоль и перезаписью в другой файл. Имя файла примите compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

  5. Запишите в текстовый файл прописные буквы латинского алфавита и их коды.

Пример3. Написать программу чтения из текстового файла массива строк, вывода этих строк на консоль и записи их в другой файл.

Для решения примера используем функции: fgets() – для чтения строк из текстового файла, fputs() – для записи строк в текстовый файл. Содержание текстового файла для считывания – обложка книги [3]

=============================================

THE

_____________________________________________

C

_____________________________________________

PROGRAMMING

LANGUAGE

=============================================

Second Edition

BRIAN W. KERIGHAN

DENNIS M. RITCHIE

AT & T Bell Laboratories

Murray Hill, New Jersey

Prentice Hall PTR, Upper Saddle River, New Jersey 07458

_________________________________________________________

Файлу, из которого будет считываться информация, присвоим имя data3.txt, файлу, куда она будет записываться, – data33.txt.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

int main(void) {

char str[255+1];

char data3[] = "D:\\data3.txt";

char data33[] = "D:\\data33.txt";

FILE *fid, *fid2;

errno_t err;

if ((fopen_s(&fid, "D:\\data3.txt", "r")) ||

(err = fopen_s(&fid2, "D:\\data33.txt", "w")) != 0)

{ printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: ");

_getch();

return -1; }

while (fgets(str, 255, fid) != NULL) // чтение из data3.txt

{

fputs(str, stdout); // вывод на консоль

fputs(str, fid2); // запись в файл data33.txt

}

fclose(fid);

fclose(fid2);

printf(" Read the information was produced from a file %s\n", data3);

printf(" Recorded information has been made to the file %s\n", data33);

printf("\n Press any key: ");

_getch();

return 0;

}

В программе с помощью логического условия «или» ( || ) производится проверка корректности открытия файла data3.txt для чтения и файла data33.txt для записи. Вместо функции fopen() используется функция fopen_s(), которая применяется в MS Visual Studio.

Функция fgets() считывает строки из файла, на который имеется указатель *fid, и записывает их в символьный массив str[256]. Одно поле этой функции используется для определения количества считываемых символов с учетом символа завершения строки.

Первая функция fputs()нужна для вывода информации на консоль с помощью определения стандартного выходного потока stdout, который указывает на «обычное» средство вывода – дисплей. Вторая функция fputs() выводит символьный массив str[] в файл data33.txt с помощью файлового указателя *fid2. Вывод на дисплей и запись в файл будут осуществляться до тех пор, пока при чтении из файла data3.txt не обнаружится признак конца файла, т.е. NULL. Проверку можно выполнять также по числу считанных символов, а именно n–1, т.е. в данном случае 255 символов из 256.

Результат выполнения программы с выводом текстовой информации на консоль представлен на рис.12.4.

Р ис.12.4. Консольный вывод содержимого текстового файла

Р езультат записи информации в текстовый файл показан на рис.12.5.

Рис.12.5. Результат записи текстовой информации в текстовый файл

Задание3

  1. Подсчитайте число итераций, выполняемых функцией while().

  2. Вывод на консоль выполните с помощью функции printf(), а запись в файл – посредством функции fprintf().

  3. Напишите программу ввода строк с клавиатуры и записи введенной информации в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа. В качестве вводимой информации используйте название дисциплин, которые вы изучаете на данный момент, а также специальность на которой вы учитесь.

  4. Напишите программу записи в текстовый файл compX.txt матрицы вещественных случайных чисел из интервала [–X; X]. Произведите считывание матрицы из файла с выводом ее значений на консоль и записью в другой текстовый файл. Размер матрицы примите n×m, где n = 3Х, m=2X, где Х – номер компьютера, на котором выполняется лабораторная работа.

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

Примечание. Для п.5 задания 3 примените массив указателей для считывания строк разной длины.

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

Для решения примера используем функции fprintf(), fgets(), atoi(), fscanf().

Программный код решения примера

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#define n 4 // число строк матрицы

#define m 3 // число столбцов матрицы

#define N 123 // число считываемых строк из текстового файла

int main(void) {

int i, j = 0;

int A[n*m] = {1,2,3,4,5,6,7,8,9,10,11,12};

int B[n*m];

FILE *fid;

char *str[] = {"aza","baza","qwerty"};

char str2[N][80]; // буферный массив

// Обнуление массива B[n*m]

for (i = 0; i < n*m; ++i)

B[i] = 0;

if ((fid = fopen("D:\\data4.txt", "w")) == NULL)

{printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: "); _getch(); return -1; }

// Запись в файл data4.txt

fprintf(fid, "\n\t The lines are:\n");

for (i = 0; i < m; ++i) fprintf(fid,"\t %s\n", str[i]);

for (i = 0; i < n*m; ++i)

fprintf(fid, " %3d", A[i]);

fclose(fid);

printf("\n\t From file \"data4.txt\":\n");

if ((fid = fopen("D:\\data4.txt", "r")) == NULL)

{printf("\n\t The file could not be opened.\n ");

printf("\n Press any key: "); _getch(); return -1; }

// Чтение из файла data4.txt

for (i = 0; (fgets(str2[i], 80, fid) != NULL) && (i < N); ++i)

printf(" %s",str2[i]);

fclose(fid);

if ((fid = fopen("D:\\data4.txt", "r")) == NULL)

{printf("\n\t Error! You can not open the file \n ");

printf("\n Press any key: "); _getch(); return -1; }

// Повторное чтение из файла data4.txt

for (i = 0; fscanf (fid, "%s", str2[i]) != EOF; ++i)

if (atoi(str2[i]))

{ B[j] = atoi(str2[i]); ++j; }

fclose(fid);

printf("\n\n\t The reconfigured array:\n");

for (i = 0; i < n; ++i) {

printf("\n\t");

for (j = 0; j < m; ++j)

printf("%5d", B[i*m+j]); }

printf("\n\n Press any key: ");

_getch();

return 0;

}

Для форматированной записи в текстовый файл и чтения из файла применены массивы указателей *str[], str2[123][80]. Чтение из файла одномерного массива целых чисел выполняется с помощью функции atoi(), значения целых чисел заносятся сначала в одномерный массив B[n*m]. После закрытия файла data4.txt этот же массив выводится на консоль в виде двухмерной матрицы размера 4×3. Форматированная запись строк и одномерного массива в файл data4.txt производится с помощью функции fprintf(). Первое чтение информации из текстового файла осуществляется посредством функции fgets(), что позволяет практически точно копировать расположение строк текстового файла на консоль (дисплей). Функция fscanf() используется для форматированного чтения информации из текста с последующим выделением целых чисел с помощью функции atoi().

В озможный результат выполнения программы представлен на рис.12.6.

Рис.12.6. Содержимое текстового файла и преобразованного массива

Задание4

  1. Для вывода информации из текстового файла поочередно используйте функции fgets() и fscanf().

  2. Инициализацию массива А выполните как инициализацию двухмерной матрицы с возможными сочетаниями числа строк и столбцов.

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

  4. Массивы чисел определите как вещественные.

  5. Размерность массива задайте с клавиатуры и заполните его натуральными числами по строкам. Предусмотрите проверку возможности преобразования одномерного массива в двухмерный. Если возможно преобразование одномерного массива, то выведете двухмерный массив в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

Пример5. Написать программу добавления слов в текстовый файл с контролем на консоли [9].

В текстовый файл запишем название книги и авторов [3]. Затем будем добавлять слова, символы и т.д.

Для программного решения примера используем функции файлового ввода / вывода fprintf(), fgets() и rewind(). Кроме того, подключим библиотеку locale.h и объявим прототип функции, что позволит использовать шрифты русского алфавита:

#include <locale.h>

setlocale( LC_ALL, "Russian" );// setlocale( LC_ALL, "rus" );

или

setlocale( LC_ALL, ".1251" );//кодовая страница Windows1251

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#include <locale.h>

#define MAX 40

int main(void) {

FILE *fid;

char words[MAX+1];

char str_name[] = "D:\\data5.txt";

setlocale( LC_ALL, "Russian");

// setlocale( LC_ALL, ".1251");

if ( (fopen_s(&fid, str_name, "a+") ) != 0)

{fprintf(stdout, "\n\t Файл не может быть открыт \"%s\".\n ", str_name); printf("\n Нажмите любую клавишу: ");

_getch(); return -1; }

printf("\n\t Введите слова для включения их в файл \"%s\"\n\t\

и нажмите клавишу Enter в начале строки для завершения ввода\n\t: ", str_name);

// Запись в файл data5.txt

while (gets_s(words, MAX) != NULL && words[0] != '\0')

{printf("\t: "); fprintf(fid," %s\n", words); }

puts("\t Содержимое файла:");

// Устанавливает указатель текущей позиции в начало файла

rewind(fid);

// Сканирование файла

while (fgets(words, MAX, fid) != '\0')

printf("\t%s", words);

if (fclose(fid) != 0)

fprintf(stderr, "\n\t Ошибка при закрытии файла \"%s\"\n", str_name);

printf("\n\n Нажмите любую клавишу: ");

_getch();

return 0;

}

В программе введены две проверки: на открытие файла if (!= 0) и на его закрытие if ( != 0), позволяющие исключить аварийный выход из программы. Использование в функции форматного вывода fprintf() ключевого слова stdout позволяет выводить сообщения на консоль – дисплей пользователя.

Вместо стандартной функции gets(), приработе с которой появляются предупреждения, использована функция gets_s(), которую поддерживает MS Visual Studio. Предупреждения возникают и при обращении к функции fopen(). Вместо нее применена fopen_s() в следующем формате записи:

fopen_s(&fid, "D:\\data5.txt","a+");

Если файл data5.txt сохранить, то при последующих выполнениях программы в него можно будет дописывать данные. Это обеспечивает режим "a+" функции fopen_s().

В озможный результат выполнения программы показан на рис.12.7.

Рис.12.7. Пример записи в файл и чтения из файла

Задание5

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

  2. В программу вместо функции fgets() включите функцию fscanf(). Отметьте результат записи и чтения некоторого количества строк, состоящих из нескольких слов.

  3. Отметье результат выполнения программы, если изменить имя текстового файла на диске D.

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

Для решения примера используем функции fseek() и ftell().

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#define MAX 79

#define file "D:\\data6.txt" // запись в прямом порядке

#define file2 "D:\\data66.txt" // запись в обратном порядке

int main(void) {

char ch, str[MAX+1];

long n, m;

FILE *fid, *fid2;

if ( fopen_s(&fid, file, "w") ) {

fprintf(stdout, "\n\t The file could not be opened.\n ");

printf("\nPress any key: ");

_getch(); return -1; }

printf("\n\t Enter a few lines and press Enter to complete before the new line\n\t: ");

// Запись в файл data6.txt

while (gets_s(str, MAX) != NULL && str[0] != '\0')

{ printf("\t: "); fprintf(fid," %s\n", str); }

fclose(fid);

if ( fopen_s(&fid, file, "r") ) {

fprintf(stdout, "\n\t File could not be opened.\n");

printf("\n Press any key: ");

_getch(); return -1; }

if ( fopen_s(&fid2, file2, "w") ) {

fprintf(stdout, "\n\t File could not be opened.\n");

printf("\n Press any key: ");

_getch(); return -1; }

//Переход в конец файла

fseek(fid, 0L, SEEK_END);

m = ftell(fid);

for (n = 1L; n <= m; n++) {

fseek(fid, -n, SEEK_END);

ch = getc(fid);

if (ch != '\n') {

printf(" "); putchar(ch);

fprintf(fid2, " "); putc(ch, fid2); }

}

putchar('\n');

fclose(fid);

fprintf(fid2, "%c", '\n');

fclose(fid2);

printf("\n Result see the files, \"%s\" and \"%s\"\n", file, file2);

printf("\n Press any key: ");

_getch();

return 0;

}

Опишем работу функций fseek() и ftell()[9].

Функция fseek()имеет следующую форматную запись:

fseek(fid, 0L, SEEK_END);

Она определяет позицию со смещением в 0 байт от конца файла (именованная константа SEEK_END). Суффикс L означает тип long int.

Строка с функцией ftell() определяет количество байтов от начала до конца указанного файла которое записывается в переменную m:

m = ftell(fid);

Рассмотрим следующий программный цикл.

for ( n = 1L; n <= m; n++ )

{

fseek( fid, -n; SEEK_END );

ch = getc( fid );

if ( ch!= '\n' ) {

printf(" "); putchar( ch );

fprintf( fid2, " " ); putc( ch, fid2 ); }

}

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

Возможные результаты выполнения программы приведены на рис.12.8–12.10.

Р ис.12.8. Результат обратного считывания информации из файла

Р ис.12.9. Результат записи информации в файл

Рис.12.10. Результат записи информации в файл в обратном порядке

Задание6

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

  2. Вместо функции putchar() примените printf().

  3. Вместо функции putc() примените функцию с тем же действием.

  4. Подготовьте текстовый файл со своими фамилией, инициалами, номером группы, специальности. Выполните чтение из этого файла в обратном порядке, выведите на консоль и запишите в дополнительный текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

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

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

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

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#define MAX 39 // предполагаемое число символов в имени

#define file "D:\\data7.dat"

#define file2 "D:\\data77.dat"

int main(void) {

int number, i = 1, j = 1; // номер ячейки

char name[MAX+1]; // имя ячейки (владельца)

long double sum; // сумма денег в у.е.

FILE *fid, *fid2;

if ( fopen_s(&fid, file, "w") )

{fprintf(stdout, "\n\t File could not be opened\n");

printf("\n Press any key: ");

_getch(); return -1; }

printf("\n Enter through blanks number of a cell,\n a name of the owner and the sum of money.\nType Ctrl+Z to exit at the beginning of a new line: \n\n");

printf(" %3d) ", i);

scanf_s("%d%s%lf", &number, name, MAX, &sum);

// Запись в файл data7.dat

while ( !feof(stdin)) { // stdin - поток с клавиатуры

fprintf(fid, " %3d\t %-15s %7.2f\r\n", number, name, sum);

printf(" %3d) ", ++i);

scanf_s("%d%s%lf", &number, name, MAX, &sum);

}

fclose(fid);

if ( fopen_s(&fid, file, "r") ) {

fprintf(stdout, "\n\t File could not be opened\n");

printf("\n Press any key: ");

_getch(); return -1; }

if ( fopen_s(&fid2, file2, "w") ) {

fprintf(stdout, "\n\t File could not be opened\n");

printf("\n Press any key: ");

_getch(); return -1; }

// Вывод на консоль

printf("\n %s\t %s\t\t %5s", "The number of cell","Name","Sum");

// Чтение из файла data7.dat

fscanf_s(fid, "%d%s%Lf", &number, name, MAX, &sum);

fprintf(fid2, "\r\n %s\t\t %s\t\t %5s\r\n", "The number of cell", "Name", "Sum");

i = 1;

while ( !feof(fid)) { // пока не конец файла

// Вывод на консоль

printf("\n %3d\t\t\t %-17s %0.2f", number, name, sum);

// Запись в файл data77.dat

fprintf(fid2," %3d) %3d\t\t\t %-17s %0.2f\r\n",i++,number,name, sum);

// Чтение из файла data7.dat

fscanf_s(fid, "%d%s%Lf", &number, name, MAX, &sum);

}

fclose(fid);

fclose(fid2);

printf("\n\n\n Result see the files, \"%s\" and \"%s\"\n", file, file2);

printf("\n Press any key: ");

_getch();

return 0;

}

В программе использована функция feof(), которая проверяет, достигнут ли конец файла, связанного с потоком (указателем на файл) fid.

Н а рис.12.11 показан возможный результат выполнения программы.

Рис.12.11. Консольный вывод содержимого файла

Следует обратить внимание на прекращение ввода данных с клавиатуры с помощью комбинации клавиш Ctrl+Z.

Задание7

  1. Вместо оператора цикла while примените оператор цикла for.

  2. Отсортируйте записи владельцев ячеек по убыванию величины суммарной денежной суммы.

  3. Подготовьте форматированный текстовый файл с именем compX, где Х – номер компьютера, на котором выполняется лабораторная работа. Затем информацию из файла выведите на консоль.

Пример8. Написать программу пакетной записи в файл произвольного доступа массива данных и вывода этого пакета на консоль.

При решении примера применим функции fwrite() и fread() для бинарной записи и считывания информации.

Программный код решения примера

#include <stdio.h>

#include <conio.h>

#define MAX 20

#define n 5

#define m 4

#define file "D:\\data8.txt"

int main(void)

{

//Матрица 5х4

int mass[MAX][MAX] = {

{1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,16}, {17,18,19,20} };

int mass2[MAX][MAX]; // вспомогательная матрица

int i, j;

// Массив из 5 указателей

char *str[] = {

"Brian W. Kernighan",

"Dennis M. Ritchie",

"Stephen Prata",

"Herbert Shildt",

"The C Programming Language"

};

char *str2[n]; // вспомогательный массив указателей

FILE *fid;

if ( fopen_s(&fid, file, "wb") ) {

fprintf(stdout, "\n\t File could not be opened\n");

printf("\n Error! Press any key: ");

_getch(); return -1; }

fwrite(str, sizeof(char), sizeof(str)/sizeof(char), fid);

fwrite(mass, sizeof(int), sizeof(mass)/sizeof(int), fid);

fclose (fid);

if ( fopen_s(&fid, file, "rb") )

{

fprintf(stdout, "\n\t File could not be opened\n");

printf("\n Press any key: ");

_getch();

return -1;

}

fread(str2, sizeof(char), sizeof(str)/sizeof(char), fid);

fread(mass2, sizeof(int), sizeof(mass2)/sizeof(int), fid);

// Чтение элементов из файла

printf("\n\t From a file \"%s\": \n\n", file);

for (i = 0; i < n; ++i)

printf("\t %-15s\n", str2[i]);

printf("\n\t Matrix from a file \"%s\":\n", file);

for (i = 0; i < n; ++i)

{

printf("\n\t");

for (j = 0; j < m; ++j)

printf(" %3d", mass2[i][j]);

}

fclose(fid);

printf("\n\n\n Press any key: ");

_getch();

return 0;

}

Функция fwrite()записывает в файл заданное количество байт из буфера памяти, адрес которого передан ей в качестве параметра. Данные записываются с того места в файле, которое обозначено указателем позиции файла. Функция fread()считывает заданное количество байт, начиная с текущей позиции файла в буфер памяти, адрес которого передан ей в качестве параметра.

В программе пакетная запись информации – набора строк и матрицы целых чисел производится через двоичный поток с помощью функций fwrite(). Чтение информации из двоичного файла осуществляется функцией fread(). Форматы записи обеих функций одинаковы, так как в них требуется установить количество объектов с заданным размером байт, которые определяются функцией sizeof().

Результат выполнения программы представлен на рис.12.12 и 12.13.

Р ис.12.12. Результат чтения из файла бинарной информации

Рис.12.13. Результат записи в текстовый файл бинарной информации

Как видно из рис. 12.12 и 112.13, информация на консоли соответствует исходной информации, а в двоичном файле она не подлежит непосредственному восприятию.

Примечание. Вид бинарной информации в текстовом файле зависит от установленных шрифтов.

Задание8

  1. Запишите двоичную информацию в файлы с расширением .dat, .doc, .bin. Проанализируйте файлы после их открытия.

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

  3. Вместо массива указателей примените схему с двухуровневой адресацией.

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

  5. Перезапишите информацию из двоичного файла в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]