Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
otvety_infa.docx
Скачиваний:
1
Добавлен:
04.08.2019
Размер:
187.42 Кб
Скачать
  1. Организация работы с файлами. Открытие, закрытие и режимы доступа.

Переменная типа указатель на файл: FILE *f

Открыть файл можно с помощью следующей конструкции:

f = fopen (“ имя_ файла”, “ режим_ доступа”);

Режим доступа – это параметр, характеризующий как должен использоваться данный файл.

’r’ -файл открывается для чтения (файл должен существовать на диске);

’w’ - файл открывается для записи; если файла с указанным именем нет, то он создаётся; если файл существует, то старое содержимое файла уничтожается;

’а’ - файл открывается, либо создаётся для дозаписи в конец файла;

’r+’ – файл открывается для чтения и записи (файл должен существовать).

’w+’ – файл открывается для чтения и записи; старое содержимое, если файл существовал, теряется.

’а+’ – файл открывается, либо создаётся для чтения уже существующей информации и добавления новой в конец файла.

Операция закрытия файла имеет вид:

fclose (имя файла), например: fclose (fp);

  1. Основные файловые функции обработки данных.

Открытие файла при помощи fopen

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

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

Они определяются как

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

FILE *freopen(const char *path, const char *mode, FILE *fp);

Функция fopen по сути представляет собой "обертку" более высокого уровня системного вызова open операционной системы Unix. Аналогично, fclose является оберткой системного вызова Unix close, а сама структура FILE языка Си зачастую обращается к соответствующему файловому дескриптору Unix. В POSIX-окружении функция fdopen может использоваться для инициализации структуры FILE файловым дескриптором. Тем не менее, файловые дескрипторы как исключительно Unix-концепция не представлены в стандарте языка Си.

Параметр mode (режим) для fopen и freopen должен быть строковый и начинаться с одной из следующих последовательностей:

режим описание начинает с..

r rb открывает для чтения начала

w wb открывает для записи (создает файл в случае его отсутствия). Удаляет содержимое и перезаписывает файл. начала

a ab открывает для добавления (создает файл в случае его отсутствия) конца

r+ rb+ r+b открывает для чтения и записи начала

w+ wb+ w+b открывает для чтения и записи. Удаляет содержимое и перезаписывает файл. начала

a+ ab+ a+b открывает для чтения и записи (добавляет в случае существования файла) конца

Значение "b" зарезервировано для двоичного режима С. Стандарт языка Си описывает два вида файлов — текстовые и двоичные — хотя операционная система не требует их различать (однако, для некоторых компиляторов, например LCC, указание 'b' при работе с бинарным файлом принципиально важно!). Текстовый файл - файл, содержащий текст, разбитый на строки при помощи некоторого разделяющего символа окончания строки или последовательности (в Unix - одиночный символ перевода строки; в Microsoft Windows за символом перевода строки следует знак возврата каретки). При считывании байтов из текстового файла, символы конца строки обычно связываются (заменяются) с переводом строки для упрощения обработки. При записи текстового файла одиночный символ перевода строки перед записью связывается (заменяется) с специфичной для ОС последовательностью символов конца строки. Двоичный файл - файл, из которого байты считываются и выводятся в "сыром" виде без какого-либо связывания (подстановки).

При открытом файле в режиме обновления ( '+' в качестве второго или третьего символа аргумента обозначения режима) и ввод и вывод могут выполняться в одном потоке. Тем не менее, запись не может следовать за чтением без промежуточного вызова fflush или функции позиционирования в файле (fseek, fsetpos или rewind), а чтение не может следовать за записью без промежуточного вызова функции позиционирования в файле. [1]

Режимы записи и добавления пытаются создать файл с заданным именем, если такого файла еще не существует. Как указывалось выше, если эта операция оканчивается неудачей, fopen возвращает NULL.

[править] Закрытие потока при помощи fclose

Функция fclose принимает один аргумент: указатель на структуру FILE потока для закрытия.

int fclose(FILE *fp);

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

[править] Чтение из потока

[править] при помощи fgetc

Функция fgetc применяется для чтения символа из потока.

int fgetc(FILE *fp);

В случае успеха, fgetc возвращает следующий байт или символ из потока (зависит от того, файл "двоичный" или "текстовый" (как выше обсуждалось). В противном случае, fgetc возвращает EOF. (Отдельный тип ошибок можно определить вызовом ferror или feof с указателем на файл.)

Стандартный макрос getc также определен в <stdio.h>, успешно работая как fgetc, кроме одного: будучи макросом, он может обрабатывать свои аргументы более одного раза.

Стандартная функция getchar также определена в <stdio.h>, она не принимает аргументов, и эквивалентна getc(stdin).

[править] "Ловушка" EOF

Распространенной ошибкой является использование fgetc, getc или getchar для присваивания результата переменной типа char перед сравнением его с EOF. Следующий фрагмент кода демонстрирует эту ошибку, а рядом приведен корректный вариант:

Ошибка Правильно

char c;

while ((c = getchar()) != EOF) {

putchar(c);

}

int c;

while ((c = getchar()) != EOF) {

putchar(c);

}

Нужно учитывать систему, в которой тип char, длина которого составляет 8 бит, представляет 256 различных значений. getchar может возвращать любой из 256 возможных символов, а также может возвращать EOF для обозначения конца файла, т.е. всего 257 возможных возвращаемых значений.

Когда результат getchar присваивается переменной типа char, которая может представить лишь 256 различных значений, происходит вынужденная потеря информации - при сжатии 257 значений в 256 "мест" происходит коллизия. Значение EOF при конвертации в char становится неотличимым от любого из остальных 256 символов. Если этот символ обнаружен в файле, код, приведенный выше, может принять его за признак конца файла, или, что еще хуже, если тип char - беззнаковый, тогда с учетом того, что EOF - значение отрицательное, оно никогда не сможет стать равным любому беззнаковому char, и таким образом, пример выше не закончится на метке конца файла, а будет выполняться вечно, повторно печатая символ, получающийся при конвертации EOF в char.

В системах, где int и char одинакового размера, даже "правильный" вариант будет работать некорректно из-за сходства EOF и другого символа. Правильным вариантом обработки подобной ситуации является проверка feof и ferror после того, как getchar вернет EOF. Если feof определит, что конец файла еще не достигнут, а ferror "сообщит", что ошибок нет, то EOF, возвращенный getchar может считаться текущим символом. Такие дополнительные проверки делаются редко, так как большинство программистов считает, что их код никогда не будет выполняться на подобных системах с "большим char". Другой способ состоит в использовании проверки при компиляции, что UINT_MAX > UCHAR_MAX, которая хотя бы предотвратит компиляцию на подобных системах.

[править] при помощи fgets

Функция fgets применяется для чтения строки из потока. Считывание происходит до тех пор пока не будет достигнут конец строки (\n) или длина строки, в которую происходит считывание. Предположим, у нас есть файл some_file.txt с текстом

палиндромы

А в Енисее - синева.

А лама мала.

А лис, он умён - крыса сыр к нему носила. (И. Бабицкий)

#include <stdio.h>

#include <string.h>

int main (int argc, char* argv[]) /* argc хранит количество параметров, а argv[] указатели на эти параметры.

Например если мы запустим выполняемый файл "fgets_example param1 param2" то argc будет равно 2, а argv[] = {"fgets_example", "param1", "param2"}*/

{

FILE *file;

char *fname = "some_file.txt";

char result_sting[20]; //Строка в 20 символов

file = fopen(fname,"r");

if(file == 0)

{

printf("не могу открыть файл '%s'",fname);

return 0;

}

int i=0;

char *real_tail;

while(fgets(result_sting,sizeof(result_sting),file))

{

real_tail="";

printf("Строка %d:Длина строки - %d:",i++,strlen(result_sting));

if(result_sting[strlen(result_sting)-1] == '\n')//проверяем является ли последний элемент в строке символом ее окончания

{

real_tail="\\n";

result_sting[strlen(result_sting)-1]='\0';

};// эта часть кода добавленна лишь для отображения символа конца строки в консоль без перевода на новую строку

printf("%s%s\n",result_sting,real_tail);

}

fclose(file);

return 0;

}

в результате выполнения мы получим

Строка 0:Длина строки - 11:палиндромы\n

Строка 1:Длина строки - 19: А в Енисее - си

Строка 2:Длина строки - 6:нева.\n

Строка 3:Длина строки - 17: А лама мала.\n

Строка 4:Длина строки - 19: А лис, он умён

Строка 5:Длина строки - 19:- крыса сыр к нему

Строка 6:Длина строки - 19:носила. (И. Бабицки

Строка 7:Длина строки - 2:й)

Функция strlen определяет длину строки по количеству символов до '\0' так например

printf("%d",strlen("123 \0 123")); //выведет 4

[править] fwrite

В языке программирование Си функции fread и fwrite соответственно реализуют файловые операции ввода и вывода. fread и fwrite объявлены в <stdio.h>.

[править] Запись в файл при помощи fwrite

fwrite определяется как

int fwrite ( const void * array, size_t size, size_t count, FILE * stream );

Функция fwrite записывает блок данных в поток. Таким образом запишется массив элементов count в текущую позицию в потоке. Для каждого элемента запишется size байт. Индикатор позиции в потоке изменится на число байт, записанных успешно. Возвращаемое значение будет равно count в случае успешного завершения записи. В случае ошибки возвращаемое значение будет меньше count.

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

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

int main(void)

{

FILE *fp;

size_t count;

char const *str = "привет\n";

fp = fopen("пример.txt", "wb");

if(fp == NULL) {

perror("ошибка открытия пример.txt");

return EXIT_FAILURE;

}

count = fwrite(str, 1, strlen(str), fp);

printf("Записано %lu байт. fclose(fp) %s.\n", (unsigned long)count, fclose(fp) == 0 ? "успешно" : "с ошибкой");

return 0;

}

[править] Запись в поток при помощи fputc

Функция fputc применяется для записи символа в поток.

int fputc(int c, FILE *fp);

Параметр c "тихо" конвертируется в unsigned char перед выводом. Если прошло успешно, то fputc возвращает записанный символ. Если ошибка, то fputc возвращает EOF.

Стандартный макрос putc также определен в <stdio.h>, работая в общем случае аналогично fputc, за исключением того момента, что будучи макросом, он может обрабатывать свои аргументы более одного раза.

Стандартная функция putchar, также определенная в <stdio.h>, принимает только первый аргумент, и является эквивалентной putc(c, stdout), где c является упомянутым аргументом.

[править] Пример использования

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

#include <stdio.h>

#include <stdlib.h>

int main(void)

{

char buffer[5] = {0}; /* инициализируем нулями */

int i, rc;

FILE *fp = fopen("мойфайл", "rb");

if (fp == NULL) {

perror("Ошибка при открытии \"мойфайл\"");

return EXIT_FAILURE;

}

for (i = 0; (rc = getc(fp)) != EOF && i < 5; buffer[i++] = rc)

;

fclose(fp);

if (i == 5) {

puts("Прочитанные байты...");

printf("%x %x %x %x %x\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]);

} else

fputs("Ошибка чтения файла.\n", stderr);

return EXIT_SUCCESS;

}

10. Структуры в языке Си. Понятие шаблона и переменной структуры.

Структура – это совокупность нескольких переменных, часто различных типов [13.1]. В структурах совокупность переменных объединяют под одним именем. Переменные, из которых состоит структура, называются ее членами. Члены структуры еще называются элементами или полями [13.2].

С помощью структур удобно размещать в смежных полях связанные между собой элементы информации. В структуре могут быть собраны различные объекты – переменные, массивы, указатели, другие структуры и т.д., которые для удобства работы с ними сгруппированы под одним именем. Если в массиве собраны переменные одного типа (например, float), то в структуре могут быть переменные различных типов. Объявление структуры создает шаблон, который можно использовать для создания ее объектов (то есть экземпляров этой структуры) [13.2]. При объявлении структуры определяется агрегатный тип данных, но не переменная

Определение структуры состоит из двух шагов:

  1. объявление шаблона структуры (задание нового типа данных, определенного пользователем);

  2. определение переменных типа объявленного шаблона [13.3].

Имена шаблонов должны быть уникальными в пределах их области определения, для того чтобы компилятор мог различать типы шаблонов. Задание шаблона осуществляется с помощью ключевого слова struct, за которым следует имя шаблона структуры и списка элементов, заключенных в фигурные скобки [13.3]. Имена элементов в одном шаблоне также должны быть уникальными. Задание только шаблона не влечет резервирования памяти компилятором. Шаблон предоставляет компилятору необходимую информацию об элементах структурной переменной для резервирования места в оперативной памяти и организации доступа к ней при определении структурной переменной и использовании ее отдельных элементов [13.3].

Рассмотрим шаблон структуры для определения имени и фамилии работника (служащего – employee), его возраста, почасовой оплаты:

struct employee {

char Name [20+1]; // Имя

char Surname [20+1]; // Фамилия

int age; // возраст

double hourlysalary; // почасовой оклад

};

Как видно, шаблон структуры struct employee состоит из символьных массивов типа char, целого числа типа int и числа с плавающей точкой и двойной точности типа double. Описания элементов производится в фигурных скобках, после закрывающей скобки обязательно должна быть точка с запятой.

Определение структуры начинается с ключевого слова struct. Идентификатор employee является именем-этикеткой (tag name), дескриптором. Имя-этикеткаemployee именует структуру и используется совместно с ключевым словом struct для объявления переменных структурного типа [13.4].

Переменные структуры объявляются так же, как и переменные других типов. На основе вышеприведенного шаблона сделаем несколько объявлений новых структурных переменных:

struct employee new_ employee, * employeePtr, stack[120];

В приведенном объявлении new_employee – переменная типа struct employee, *employeePtr – указатель на struct employee, emstack[120] – массив из 120 элементов типа struct employee.

Объявленные структурные переменные new_employee, *employeePtr, stack[102] могут быть объединены с определением структуры, а именно:

struct employee {

char Name [20+1]; // Имя

char Surname [20+1]; // Фамилия

int age; // возраст

double hourlysalary; // почасовой оклад

} new_employee, *employeePtr, stack[120];

Имя-этикетка (tag name) не является для структуры обязательным. Если определение структуры не содержит имя-этикетку, то переменные для этой структуры могут быть объявлены только в определении структуры, но не отдельным объявлением [13.1].

При создании структур часто используется ключевое слово typedef (оператор). Оно предоставляет программисту средство для создания синонимов (или псевдонимов) для ранее определенных типов данных. Часто используют typedef для того, чтобы дать укороченное имя структурному типу [13.4]. Например, оператор вида

typedef struct card Card;

определяет новый тип с именем Card как синоним типа struct card.

Ключевое слово typedef может быть использовано в определении типа структуры без имени-этикетки. Например:

typedef struct {

char *Name; // Имя

char *Surname; // Фамилия

int age; // возраст

double hourlysalary; // почасовой оклад

} Man;

создает тип Man без использования отдельного оператора typedef.

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

Созданный тип Man можно использовать для объявления структурных переменных типа struct employee, например:

Man stack[120]

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