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

Текстовые файлы

Рассмотрим работу с текстовым файлом в Си на примере. Создайте на диске С текстовый файл с именем TextFile.txt. Наберите в этом файле такие строки:

String_1 123 String_11, 456
String_2
String_3

Сохраните файл.

А это код программы на C, которая открывает наш файл и считывает из него строки:

/* *Author: @author Subbotin B.P..h> #include #define LEN 50 int main(void) { puts("Text file operations"); char cArray; FILE *pTextFile = fopen("C:\\TextFile.txt", "r"); if(pTextFile == NULL) { puts("Problems"); return EXIT_FAILURE; } while(fgets(cArray, LEN, pTextFile) != NULL) { printf("%s", cArray); } fclose(pTextFile); return EXIT_SUCCESS; }

Чтоб открыть текстовый файл в C используем функцию fopen:

FILE *pTextFile = fopen("C:\\TextFile.txt", "r");

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

Строки считываем с помощью функции fgets:

fgets(cArray, LEN, pTextFile);

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

После завершения работы с файлом, его надо закрыть:

fclose(pTextFile);

Получаем:

Русские буквы в строках тоже проходят.

Кстати, эту программу я сделал в Eclipse. Как работать с C/C++ в Eclipse можно посмотреть .

Итак, мы открыли и считали данные из текстового файла.

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

/* Author: @author Subbotin B.P..h> #include int main(void) { FILE *pTextFile = fopen("C:\\TextFileW.txt", "w"); char *cString = "This is a string"; char cNewLine = "\n"; int nVal = 123; if(pTextFile == NULL) { puts("Problems"); return EXIT_FAILURE; } fprintf(pTextFile, "%s%c", cString, cNewLine); fprintf(pTextFile, "%d", nVal); return EXIT_SUCCESS; }

Создаем текстовый файл для записи в него данных:

FILE *pTextFile = fopen("C:\\TextFileW.txt", "w");

если файл уже имеется, то он будет открыт, и все данные из него будут удалены.

C-строка cString, и число nVal записываются программой в текстовый файл. cNewLine - это просто переход на новую строку.

Записываем данные в текстовый файл с помощью функции fprintf:

fprintf(pTextFile, "%s%c", cString, cNewLine);

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

В этом разделе будут рассотрены два способа работы с фыйлами и стандартный класс MFC CFileDialog.


1. Работа с файлами в C (работает и в C++)..


    #include
    #include

Void main(void)
{
FILE *file;
char* file_name = "file.txt";
char load_string = "none";

File = fopen(file_name, "w");

Fputs("string", file);

File = fopen(file_name, "r");
if(file != 0)
{
fgets(load_string, 50 , file);
cout }
else
{
cout }
fclose(file);
} Описание функций работы с файломи находятся в библиотеке stdio.h
Сначала надо создать указатель на переменную типа FILE (FILE* file; ).
Открытие файла производится вызовом функции fopen (file = fopen(file_name, "w"); )
Первый параметр этой функции - имя файла, второй - указывает в каком режиме должен быть открыт файл. "w" - открыть для записи, "r" - открыть для чтения, "a" - дополнение файла(это наиболее используемые режимы, хотя есть и другие). Запись и считывание данных из файла осуществляется следующими функциями: fputc, fputs, fgetc, fgets, fprintf, fscanf (описание этих функций смотрите в stdio.h ).
Закрытие файла осуществляется вызовом функции fclose (fclose(file); ).

Работа с файлами с помощью MFC(классы CFile, CStdioFile, ...) и стандартный класс MFC CFileDialog.


В библиотеку MFC включено несколько классов для обеспечения работы с файлами. Рассматриваемые ниже классы наследуются от базового класса

CFile .

Класс CF ile

CFile предназначен для обеспечения работы с файлами. Он позволяет упростить использование файлов, представляя файл как объект, который можно создать, читать, записывать и т.д.

Чтобы получить доступ к файлу, сначала надо создать объект класса CFile. Конструктор класса позволяет сразу после создания такого объекта открыть файл. Но можно открыть файл и позднее, воспользовавшись методом

Open .

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

После создания объекта класса CFile можно открыть файл, вызвав метод Open . Методу надо указать путь к открываемому файлу и режим его использования. Прототип метода Open имеет следующий вид:

Virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError=NULL);

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

Второй параметр nOpenFlags определяет действие, выполняемое методом Open с файлом, а также атрибуты файла. Ниже представлены некоторые возможеые значения параметра nOpenFlags:

  • CFile::modeCreate - Создается новый файл. Если указанный файл существует, то его содержимое стирается и длина файла устанавливается равной нулю.
  • CFile::modeNoTruncate - Этот файл предназначен для использования совместно с файлом CFile::modeCreate. Если создается уже существующий файл, то его содержимое не будет удалено.

  • CFile::modeRead - Файл открывается только для чтения.
  • CFile::modeReadWrite - Файл открывается для записи и для чтения.
  • CFile::modeWrite - Файл открывается только для записи.
  • CFile::typeText - Используется классами, порожденными от класса CFile, например CStdioFile, для работы с файлами в текстовом режиме. Текстовый режим обеспечивает преобразование комбинации символа возврата каретки и символа перевода строки.
  • CFile::Binary - Используется классами, порожденными от класса CFile, например CStdioFile, для работы с файлами в двоичном режиме.
  • Необязательный параметр pError, который является указателем на объект класса CFileException , используется только в том случае, если выполнение операции с файлом вызовет ошибку. При этом в объект, указываемый pError, будет записана дополнительная информация.

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

    Идентификатор открытого файла

    В состав класса CFile входит элемент данных m_hFile типа UINT. В нем хранится идентификатор открытого файла. Если объект класса CFile уже создан, но файл еще не открыт, то в переменной m_hFile записана константа hFileNull.

    Обычно идентификатор открытого файла непосредственно не используется. Методы класса CFile позволяют выполнять практически любые операции с файлами и не требуют указывать идентификатор файла. Так как m_hFile является элементом класса, то реализация его методов всегда имеет свободный доступ к нему.

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

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

    Чтение и запись файлов

    Для доступа к файлам предназначено несколько методов класса CFile : Read, ReadHuge, Write, WriteHuge, Flush . Методы Read и ReadHuge предназначены для чтения данных из предварительно открытого файла. В 32-разрядных операционных системах оба метода могут одновременно считать из файла больше 65535 байт. Спецификация ReadHuge считается устаревшей и оставлена только для совместимости с 16-разрядными операционными системами.

    Данные, прочитанные из файла, записываются в буфер lpBuf. Параметр nCount определяет количество байт, которое надо считать из файла. Фактически из файла может быть считано меньше байт, чем запрошено параметром nCount. Это происходит, если во время чтения достигнут конец файла. Методы возвращают количество байт, прочитанных из файла.

    Для записи в файл предназначены методы Write и WriteHuge. В 32-разрядных операционных системах оба метода могут одновременно записывать в файл больше 65535 байт. Методы записывает в открытый файл nCount байт из буфера lpBuf. В случае возникновения ошибки записи, например переполнения диска, методы вызывает обработку исключения.

    Метод Flush

    Когда используется метод Write или WriteHuge для записи данных на диск, они некоторое время могут находиться во временном буфере. Чтобы убедиться, что необходимые изменения внесены в файл на диске, нужно воспользоваться методом Flush.

    Операции с файлами

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

    Для изменения имени файла класс CFile включает статический метод Rename , выполняющий функции этой команды. Метод нельзя использовать для переименования каталогов. В случае возникновения ошибки метод вызывает исключение.

    Для удаления файлов в классе CFile включен статический метод Remove , позволяющий удалить указанный файл. Этот метод не позволяет удалять каталоги. Если удалить файл невозможно, то метод вызывает исключение.

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

    Виртуальная версия метода GetStatus определяет состояние открытого файла, связанного с данным объектом класса CFile. Этот метод вызывается только тогда, когда объект класса CFile создан и файл открыт.

    Статическая версия метода GetStatus позволяет определить характеристики файла, не связанного с объектом класса CFile. Чтобы воспользоваться этим методом, необязательно предварительно открывать файл.

    Блокировка

    В состав класса включены методы LockRange и UnlockRange , позволяющие заблокировать один или несколько фрагментов данных файла для доступа из других процессов. Если приложение пытается повторно блокировать данные, уже заблокированные раньше этим или другим приложением, вызывается исключение. Блокировка представляет собой один из механизмов, позволяющих нескольким приложениям или процессам одновременно работать с одним файлом, не мешая друг другу.

    Установить блокировку можно с помощью метода LockRange . Чтобы снять установленные блокировки, надо воспользоваться методом UnlockRange . Если в одном файле установлены несколько блокировок, то каждая из них должна сниматься отдельным вызовом метода UnlockRange .

    Позиционирование

    Чтобы переместить указатель текущей позиции файла в новое положение, можно воспользоваться одним из следующих методов класса CFile - Seek, SeekToBegin, SeekToEnd. В состав класса CFile также входят методы, позволяющие установить и изменить длину файла, - GetLength, SetLength .

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

    Чтобы переместить указатель текущей позиции файла в любое место, можно воспользоваться универсальным методом

    Seek . Он позволяет переместить указатель на определенное число байт относительно начала, конца или текущей позиции указателя.

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

    SeekToBegin перемещает указатель в начало файла, а метод SeekToEnd - в его конец.

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

    GetLength . Этот метод также возвращает длину открытого файла в байтах. Метод SetLength позволяет изменить длину открытого файла. Если при помощи этого метода размер файла увеличивается, то значение последних байт не определено.

    Текущую позицию указателя файла можно определить с помощью метода

    GetPosition . Возвращаемое методом GetPosition 32-разрядное значение определяет смещение указателя от начала файла.

    Характеристики открытого файла

    Чтобы определить расположение открытого файла на диске, надо вызвать метод GetFilePath . Этот метод возвращает объект класса CString , в котором содержится полный путь файла, включая имя диска, каталоги, имя файла и его расширение.

    Если требуется определить только имя и расширение открытого файла, можно воспользоваться методом GetFileName . Он возвращает объект класса CString, в котором находится имя файла. В случае, когда нужно узнать только имя открытого файла без расширения, пользуются методом GetFileTitle .

    Следующий метод класса CFile позволяет установить путь файла. Это метод не создает, не копирует и не изменяет имени файла, он только заполняет соответствующий элемент данных в объекте класса CFile.

    Класс C

    MemFile

    В библиотеку MFC входит класс

    CMemFile , наследуемый от базового класса CFile . Класс CMemFile представляет файл, размещенный, в оперативной памяти. С объектами класса CMemFile так же, как и с объектами класса CFile . Отличие заключается в том, что файл, связанный с объектом CMemFile , расположен не на диске, а в оперативной памяти компьютера. За счет этого операции с таким файлом происходят значительно быстрее, чем с обычными файлами.

    Работая с объектами класса

    CMemFile , можно использовать практически все методы класса CFile , которые были описаны выше. Можно записывать данные в такой файл или считывать их. Кроме этих методов в состав класса CMemFile включены дополнительные методы.

    Для создания объектов класса CMemFile предназначено два различных конструктора. Первый конструктор CMemFile имеет всего один необязательный параметр nGrowBytes:

    CMemFile(UINT nGrowBytes=1024);

    Этот конструктор создает в оперативной памяти пустой файл. После создания файл автоматически открывается (не нужно вызывать метод Ope

    n).

    Когда начинается запись в такой файл, автоматически выделяется блок памяти. Для получения памяти методы класса

    CMemFile вызывают стандартные функции malloc, realloc и free . Если выделенного блока памяти недостаточно, его размер увеличивается. Увеличение блока памяти файла происходит по частям по nGrowBytes байт. После удаления объекта класса CMemFile используемая память автоматически возвращается системе.

    Второй конструктор класса CMemFile имеет более сложный прототип. Это конструктор используется в тех случаях, когда программист сам выделяет память для файла:

    CMemFile(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes=0);

    Параметр lpBuffer указывает на буфер, который будет использоваться для файла. Размер буфера определяется параметром nBufferSize.

    Необязательный параметр nGrowBytes используется более комплексно, чем в первом конструкторе класса. Если nGrowBytes содержит нуль, то созданный файл будет содержать данные из буфера lpBuffer. Длина такого файла будет равна nBufferSize.

    Если nGrowBytes больше нуля, то содержимое буфера lpBuffer игнорируется. Кроме того, если в такой файл записывается больше данных, чем помещается в отведенном буфере, то его размер автоматически увеличивается. Увеличение блока памяти файла происходит по частям по nGrowBytes байт.

    CMemFile позволяет получить указатель на область памяти, используемую файлом. Через этот указатель можно непосредственно работать с содержимым файла, не ограничивая себя методами класса CFile . Для получения указателя на буфер файла можно воспользоваться методом Detach. Перед этим полезно определить длину файла (и соответственно размер буфера памяти), вызвав метод GetLength . Detach закрывает данный файл и возвращает указатель на используемый им блок памяти. Если опять потребуется открыть файл и связать с ним оперативный блок памяти, нужно вызвать метод Attach .

    Нужно отметить, что для управления буфером файла класс

    CMemFile вызывает стандартные функции malloc, realloc и free . Поэтому, чтобы не нарушать механизм управления памятью, буфер lpBuffer должен быть создан функциями malloc или calloc .

    Класс CStdioFile

    Тем, кто привык пользоваться функциями потокового ввода/вывода из стандартной библиотеки C и C++, следует обратить внимание на класс

    CStdioFile , наследованный от базового класса CFile . Этот класс позволяет выполнять буферизированный ввод/вывод в текстовом и двоичном режиме. Для объектов класса CStdioFile можно вызывать практически все методы класса CFile. CStdioFile входит элемент данных m_pStream, который содержит указатель на открытый файл. Если объект класса CStdioFile создан, но файл еще не открыт, либо закрыт, то m_pStream содержит константу NULL. CStdioFile имеет три различных конструктора. Первый конструктор класса CStdioFile не имеет параметров. Этот конструктор только создает объект класса, но не открывает никаких файлов. Чтобы открыть файл, надо вызвать метод Open базового класса CFile .

    Второй конструктор класса

    CStdioFile можно вызвать, если файл уже открыт и нужно создать новый объект класса CStdioFile и связать с ним открытый файл. Этот конструктор можно использовать, если файл был открыт стандартной функцией fopen . Параметр метода должен содержать указатель на файл, полученный вызовом стандартной функции fopen .

    Третий конструктор можно использовать, если надо создать объект класса

    CStdioFile , открыть новый файл и связать его с только что созданным объектом.

    Для чтения и записи в текстовый файл класс CStdioFile включает два новых метода:

    ReadString и WriteString . Первый метод позволяет прочитать из файла строку символов, а второй метод - записать.

    Примеры записи и чтения из файла

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

    Открытие файла и чтение из него

    CString m_Text; …… // создание стандартной панели выбора файла Open CFileDialog DlgOpen(TRUE,(LPCSTR)"txt",NULL, OFN_HIDEREADONLY,(LPCSTR)" Text Files (*.txt) |*.txt||"); // отображение стандартной панели выбора файла Open if(DlgOpen.DoModal()==IDOK) { // создание объекта и открытие файла для чтения CStdioFile File(DlgOpen.GetPathName(),CFile::modeRead|CFile::typeBinary); // чтение из файла строки CString& ref=m_Text; File.ReadString(ref); // передается ссылка на строку m_Text }

    Открытие файла и запись из него

    CString m_Text; …… // создание стандартной панели выбора файла SaveAs CFileDialog DlgSaveAs(FALSE,(LPCSTR)"txt",NULL, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, (LPCSTR)" Text Files (*.txt) |*.txt||"); // отображение стандартной панели выбора файла SaveAs if(DlgSaveAs.DoModal()==IDOK) { // создание объекта и открытие файла для записи CStdioFile File(DlgSaveAs.GetPathName(), CFile::modeCreate|CFile::modeWrite|CFile::typeBinary); // запись в файл строки File.WriteString((LPCTSTR)m_Text); }
      находится рабочий код программы, выполненной для простоты в виде консольного приложения под MFC. Чтобы программа работала не забудте сделать следующее:

      Запустите программу - Build / Rebuild all (будут ошибки), выберите Build / Set active configuration - Win 32 Realise, выберите пункт меню "Project", далее "Settings...", закладку "C/C++", Category - Code Generation и в пункте "Use run-time library" выберите "Multithreaded". После этого сделайте опять Build / Rebuild all и программа будет работать.

    До этого при вводе-выводе данных мы работали со стандартными потоками - клавиатурой и монитором. Теперь рассмотрим, как в языке C реализовано получение данных из файлов и запись их туда. Перед тем как выполнять эти операции, надо открыть файл и получить доступ к нему.

    В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:
    FILE *myfile;

    С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения ("r"), записи ("w") или добавления ("a") и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:
    myfile = fopen ("hello.txt", "r");

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

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

    Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.

    После того, как работа с файлом закончена, принято его закрывать, чтобы освободить буфер от данных и по другим причинам. Это особенно важно, если после работы с файлом программа продолжает выполняться. Разрыв связи между внешним файлом и указателем на него из программы выполняется с помощью функции fclose() . В качестве параметра ей передается указатель на файл:
    fclose(myfile);

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

    Чтение из текстового файла и запись в него

    fscanf()

    Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:
    fscanf (myfile, "%s%d", str, &a);

    Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.

    Допустим, у нас есть файл содержащий такое описание объектов:

    Apples 10 23.4 bananas 5 25.0 bread 1 10.3

    #include main () { FILE * file; struct food { char name[ 20 ] ; unsigned qty; float price; } ; struct food shop[ 10 ] ; char i= 0 ; file = fopen ("fscanf.txt" , "r" ) ; while (fscanf (file, "%s%u%f" , shop[ i] .name , & (shop[ i] .qty ) , & (shop[ i] .price ) ) != EOF) { printf ("%s %u %.2f\n " , shop[ i] .name , shop[ i] .qty , shop[ i] .price ) ; i++; } }

    В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.

    fgets()

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

    Например:
    fgets (str, 50, myfile)

    Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа "\n", который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ "\0", добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет "\0". В таком случае "\n" в считанной строке содержаться не будет.

    #include #define N 80 main () { FILE * file; char arr[ N] ; file = fopen ("fscanf.txt" , "r" ) ; while (fgets (arr, N, file) != NULL) printf ("%s" , arr) ; printf ("\n " ) ; fclose (file) ; }

    В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.

    getc() или fgetc()

    Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.

    while ((arr[ i] = fgetc (file) ) != EOF) { if (arr[ i] == "\n " ) { arr[ i] = "\0 " ; printf ("%s\n " , arr) ; i = 0 ; } else i++; } arr[ i] = "\0 " ; printf ("%s\n " , arr) ;

    Приведенный в качестве примера код выводит данные из файла на экран.

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

    Также как и ввод, вывод в файл может быть различным.

    • Форматированный вывод. Функция fprintf (файловый_указатель, строка_формата, переменные) .
    • Посточный вывод. Функция fputs (строка, файловый_указатель) .
    • Посимвольный вывод. Функция fputc() или putc(символ, файловый_указатель) .

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

    Запись в каждую строку файла полей одной структуры:

    file = fopen ("fprintf.txt" , "w" ) ; while (scanf ("%s%u%f" , shop[ i] .name , & (shop[ i] .qty ) , & (shop[ i] .price ) ) != EOF) { fprintf (file, "%s %u %.2f\n " , shop[ i] .name , shop[ i] .qty , shop[ i] .price ) ; i++; }

    Построчный вывод в файл (fputs() , в отличие от puts() сама не помещает в конце строки "\n"):

    while (gets (arr) != NULL) { fputs (arr, file) ; fputs ("\n " , file) ; }

    Пример посимвольного вывода:

    while ((i = getchar () ) != EOF) putc (i, file) ;

    Чтение из двоичного файла и запись в него

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

    При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка "rb" или "wb".

    Тема о работе с двоичными файлами достаточно сложная, для ее изучения требуется отдельный урок. Здесь будут отмечены только особенности функций чтения-записи в файл, который рассматривается как поток байтов.

    Функции fread() и fwrite() принимают в качестве параметров:

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

    Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно "заказать" считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.

    Пример использования функций fread() и fwrite() :

    #include #include main () { FILE * file; char shelf1[ 50 ] , shelf2[ 100 ] ; int n, m; file = fopen ("shelf1.txt" , "rb" ) ; n= fread (shelf1, sizeof (char ) , 50 , file) ; fclose (file) ; file = fopen ("shelf2.txt" , "rb" ) ; m= fread (shelf2, sizeof (char ) , 50 , file) ; fclose (file) ; shelf1[ n] = "\0 " ; shelf2[ m] = "\n " ; shelf2[ m+ 1 ] = "\0 " ; file = fopen ("shop.txt" , "wb" ) ; fwrite (strcat (shelf2, shelf1) , sizeof (char ) , n+ m, file) ; fclose (file) ; }

    Здесь осуществляется попытка чтения из первого файла 50-ти символов. В n сохраняется количество реально считанных символов. Значение n может быть равно 50 или меньше. Данные помещаются в строку. То же самое происходит со вторым файлом. Далее первая строка присоединяется ко второй, и данные сбрасываются в третий файл.

    Решение задач

    1. Напишите программу, которая запрашивает у пользователя имя (адрес) текстового файла, далее открывает его и считает в нем количество символов и строк.
    2. Напишите программу, которая записывает в файл данные, полученные из другого файла и так или иначе измененные перед записью. Каждая строка данных, полученная из файла, должна помещаться в структуру.

    Записывать информацию в текстовый файл мы уже научились. – Если не научились смотрите прошлую статью. Там рассказывается и подробно описано

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

    #include

    int main ()
    {
    char s1 // Переменная будет считывать строку
    ifstream in (“C:\\\FromC\\myfile.txt” ); // Открываем файл для считывания информации
    in >>s1 ; // считываем строку
    in .close () // Закрываем файл

    cout <Выводим значение s1 на экран
    return 0 ;
    }

    Вот наипростейшая программа для считывания первой строки из текстового файла, который находится по пути
    C:\\\FromC\\myfile.txt –
    Так как это продолжение прошлой статьи , то я решил использовать тот файл, который мы там создавали. Трудностей с этим, наверное возникнуть не должно.
    Но вернемся к коду. Сначала мы открываем файл для считывания из него информации, для этого используем команду ifstream , в скобках указываем либо название файла, либо путь к файлу, как сделано у меня.(“C:\\\FromC\\myfile.txt” );
    Когда мы открыли файл, чтобы считать из него что-то, мы объявили одну переменную типа char –
    char s1
    Теперь нам осталось только присвоить переменной значение строки из файла. Это мы делаем командой in
    Обращаем внимание на угловые скобки in >>
    Собственно, как должно быть видно из комментариев к коду программы, то чтобы переменная присвоила считываемое значение, мы должны написать её после in >>
    in >>s1 ;

    Никакой особо сложной задачей это не представляется, особенно если вы уже прекрасно освоили и научились использовать материал прошлой статьи – всё абсолютно аналогично, только 2 команды другие

    Создание файла и запись в него информации С++

    ofstream out (Имя файла );
    out << (Записываемая строка );
    out .close ();
    =============================

    Чтение текста из файла и вывода текста на экран в C++

    ifstream in (Имя файла );
    in >> (Считываем строку );
    in .close (); (Закрываем файл )
    ============================
    Напишем простую программу, которая будет считывать ввод с клавиатуры текста и записывать его в файл:

    #include
    #include

    int main ()
    {
    \\ 3 будущие строки
    clrscsr (); // Очищаем экран

    cout <<“Wwedi pervuu stroku” ; cin >>a ; endl ;
    cout <<“Wwedi wtoruu stroku” ; cin >>b ; endl ;
    cout <<“Wwedi tretuu stroku” ; cin >>c ; endl ;
    clrscr (); //

    /*Начинаем работу с файлом*/
    ofstream out (“C:\\\FromC\\myfile.txt” ); // Открываем файл для записи
    out <Записываем первую строчку
    out <Записываем вторую строчку
    out <Записываем третью строчку
    out .close (); // Закрываем файл

    //Обнуляем переменные

    for (int i =0 ;i <=255 ;i ++)
    {a =*“” ; b =*“” ; c =*“” ;}


    ifstream in (“C:\\\FromC\\myfile.txt” );
    in >>a >>b >>c ; // Считываем каждую новую строчку в новую переменную
    in .close (); // Закрываем файл

    /* */

    for (i =0 ;a !=*“” ;i ++)
    {
    if (i >sizeof(a )) break ;
    cout <

    }
    cout <<“\n” ; \\

    /* */


    {
    if (i >sizeof(b )) break ;
    cout <
    }
    cout <<“\n” ; \\ Перевели курсор на новую строчку

    /* */

    for (i =0 ;с !=*“” ;i ++)
    {
    if (i >sizeof(c )) break ;
    cout <<с ;
    }

    return 0 ;
    }
    ===================

    В приведенных выше примерах есть один такой ОГРОМНЫЙ недостаток. Если мы будем пытаться ввести строчку, содержащую пробелы, то программа будет срабатывать не так как нам нужно. Наверное, на эту ошибку наткнулся не только я, но и многие другие люди. Поэтому я оставляю неверно приведенный код, чтобы было видно с чем можно столкнуться.

    Так как книжек дома нет, я снова стал рыскать в интернете и понаходил много всякой мудреной ерунды. Но всё-таки как-то подобрал решение своей проблемы.
    Помогло то, что читал о том, что cout поддерживает свои методы. И в интернете все советы идут на использование функции getline К моему счастью как использовать эту функцию я нашел очень быстро и потом использовал ее в коде.
    Вообще стоит упомянуть и описать эту функцию, но пока что я не особо её понимаю, просто понимаю, что её нужно использовать и понимаю как, поэтому привожу более правильный пример нашей разрабатываемой программы:

    #include
    #include

    int main ()
    {
    char a ,b ,c ; \\ 3 будущие строки
    clrscsr (); // Очищаем экран

    /* Вводим значения для переменных*/

    cout <<“Wwedi pervuu stroku” ; cin.getline(a,sizeof(a)); endl ;
    cout <<“Wwedi wtoruu stroku” ; cin.getline(a,sizeof(b)); endl ;
    cout <<“Wwedi tretuu stroku” ; cin.getline(a,sizeof(c)); endl ;
    clrscr (); // После ввода значений очистили экран

    /*Начинаем работу с файлом*/
    ofstream out (“C:\\\FromC\\myfile.txt”); // Открываем файл для записи
    out <
    Записываем первую строчку
    out <Записываем вторую строчку
    out <Записываем третью строчку
    out .close (); // Закрываем файл

    //Обнуляем переменные

    for (int i =0 ;i <=255 ;i ++)
    {a =*“” ; b =*“” ; c=*“” ;}

    /*Продолжаем работу с файлом*/

    if stream in (“C:\\\FromC\\myfile.txt” );
    in.getline(a,sizeof(a)); // а
    in.getline(b,sizeof(b)); // Считываем строчку в переменную b
    in.getline(c,sizeof(c)); // Считываем строчку в переменную c
    in .close (); // Закрываем файл

    /* Считываем посимвольно первую строку и выводим её на экран*/

    for (i =0 ;a !=*“” ;i++)
    {
    if (i >sizeof(a )) break ;
    cout <

    }
    cout <<“\n” ; \\ Перевели курсор на новую строчку

    /* Считываем посимвольно вторую строку и выводим её на экран*/

    for (i =0 ;b !=*“” ;i ++)
    {
    if (i >sizeof(b )) break ;
    cout <
    }
    cout <<“\n” ; \\ Перевели курсор на новую строчку

    /* Считываем посимвольно третью строку и выводим её на экран*/

    for (i =0 ;с !=*“” ;i++)
    {
    if (i>sizeof (c )) break ;
    cout <<с[i];
    }

    getch (); \\ Ожидаем нажатия клавиши Enter
    return 0 ;
    }
    ===================

    В этом материале разобран пример посимвольного чтения информации. Так как я не описывал работу с перемнными типа char , то у начинающих могут возникнуть некоторые неудобства воспринятия кода. Просто я не знал, что тип char имеет какие-то особенности и думал всё проще. Поэтому некоторые непонятные моменты приведенной программы можно прочитать в следующей статье работа с char в C++ для начинающих

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

    Если мы вместе с вами поняли этот материал, то значит продвинулись на маленький шажок к своему профессионализму.

    Примечание:
    break ; – Это команда, которая выполняет выход из цикла. У нас если счетчик цикла for становится больше чем объявленный размер переменной char, то мы принудительно выходим из цикла
    != – это поставленное нами условие. Обозначает такое условие неравенство
    if(a !=b ) – Читается как если a не равно b

    endl ; – Это перевод курсора на новую строку внутри консоли (насколько я понял)
    Эта команда похожа на“\n”

    Работа с текстовыми файлами в C++.

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

      Текстовыми называются файлы, состоящие из любых символов. Они организуются по строкам, каждая из которых заканчивается символом «конец строки». Конец самого файла обозначается символом «конец файла». При записи информации в текстовый файл, просмотреть который можно с помощью любого текстового редактора, все данные преобразуются к символьному типу и хранятся в символьном виде.

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

    Для работы с файлами используются специальные типы данных , называемые потоками . Поток ifstream служит для работы с файлами в режиме чтения, а ofstream в режиме записи. Для работы с файлами в режиме как записи, так и чтения служит поток fstream .

    В программах на C++ при работе с текстовыми файлами необходимо подключать библиотеки iostream и fstream.

    Для того чтобы записывать данные в текстовый файл, необходимо:

      описать переменную типа ofstream.

      вывести информацию в файл.

      обязательно закрыть файл.

    Для считывания данных из текстового файла, необходимо:

      описать переменную типа ifstream.

      открыть файл с помощью функции open.

      закрыть файл.

    Запись информации в текстовый файл

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

      Будет создана переменная F для записи информации в файл.

      На следующим этапе файл необходимо открыть для записи. В общем случае оператор открытия потока будет иметь вид:

    F.open(«file», mode);

    Здесь F - переменная, описанная как ofstream,

    file - полное имя файла на диске,

    mode - режим работы с открываемым файлом.

    Обратите внимание на то, что при указании полного имени файла нужно ставить двойной слеш. Например, полное имя файла noobs.txt, находящегося в папке game на диске D:, нужно будет записать так:

    D:\\game\\noobs.txt.

    Файл может быть открыт в одном из следующих режимов:

    ios::in - открыть файл в режиме чтения данных, этот режим является режимом по умолчанию для потоков ifstream;

    ios::out - открыть файл в режиме записи данных (при этом информация о существующем файле уничтожается), этот режим является режимом по умолчанию для потоков ofstream;

    ios::app - открыть файл в режиме записи данных в конец файла;

    ios::ate - передвинуться в конец уже открытого файла;

    ios::trunc - очистить файл, это же происходит в режиме ios::out;

    ios::nocreate - не выполнять операцию открытия файла, если он не существует;

    ios::noreplace - не открывать существующий файл.

    Параметр mode может отсутствовать, в этом случае файл открывается в режиме по умолчанию для данного потока.

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

    Открыть файл (в качестве примера возьмем файл D:\\game\\noobs.txt) в режиме записи можно одним из следующих способов:

    // первый способ

    ofstream F;

    F.open("D:\\game\\noobs.txt", ios::out);

    //второй способ, режим ios::out является режимом по умолчанию

    // для потока ofstream

    ofstream F;

    //третий способ объединяет описание переменной и типа поток

    //и открытие файла в одном операторе

    ofstream F ("D:\\game\\noobs.txt", ios::out);

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

    Если вы хотите открыть существующий файл в режиме до записи, то в качестве режима следует использовать значение ios::app.

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

    Например, для записи в поток F переменной a, оператор вывода будет иметь вид:

    Для последовательного вывода в поток G переменных b, c, d оператор вывода станет таким:

    G<

    Закрытие потока осуществляется с помощью оператора:

    ПРИМЕР:

    Создать текстовый файл D:\\game\\noobs.txt и записать в него n вещественных чисел.

    #include "stdafx.h"

    #include

    #include

    #include

    using namespace std;

    int main()

    setlocale (LC_ALL, "RUS");

    int i, n;

    double a;

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

    ofstream f ;

    //открываем файл в режиме записи,

    //режим ios :: out устанавливается по умолчанию

    f.open("D:\\game\\noobs.txt", ios::out);

    //вводим количество вещественных чисел

    cout <<" n ="; cin >> n ;

    //цикл для ввода вещественных чисел

    //и записи их в файл

    for (i=0; i

    cout<<"a=";

    //ввод числа

    cin>>a;

    f<

    //закрытие потока

    f.close();

    system("pause");

    return 0;

    _______________________________________________________________

    Для того чтобы прочитать информацию из текстового файла, необходимо описать переменную типа ifstream . После этого нужно открыть файл для чтения с помощью оператора open . Если переменную назвать F, то первые два оператора будут такими:

    F.open("D:\\game\\noobs.txt", ios::in);

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

    Например, для чтения из потока F в переменную a, оператор ввода будет выглядеть так:

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

    Здесь F - имя потока функция возвращает логическое значение: true или false, в зависимости от того достигнут ли конец файла. Следовательно, цикл для чтения содержимого всего файла можно записать так:

    //организуем для чтения значений из файла, выполнение

    //цикла прервется, когда достигнем конец файла,

    //в этом случае F.eof() вернет истину

    while (!F.eof())

    ПРИМЕР:

    В текстовом файле D:\\game\\noobs.txt хранятся вещественные числа, вывести их на экран и вычислить их количество.

    #include "stdafx.h"

    #include

    #include

    #include

    #include

    using namespace std;

    int main()

    setlocale (LC_ALL, "RUS");

    int n=0;

    float a;

    fstream F;

    //открываем файл в режиме чтения

    F.open("D:\\game\\noobs.txt");

    //если открытие файла прошло корректно, то

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

    //когда достигнем конца файла, в этом случае F.eof() вернет истину.

    while (!F.eof())

    //чтение очередного значения из потока F в переменную a

    F>>a;

    //вывод значения переменной a на экран

    cout<

    //увеличение количества считанных чисел

    //закрытие потока

    F.close();

    //вовод на экран количества считанных чисел

    cout<<"n="<

    //если открытие файла прошло некорректно, то вывод

    //сообщения об отсутствии такого файла

    else cout<<" Файл не существует"<

    system("pause");

    return 0;

    C++. Обработка двоичных файлов

    При записи информации в двоичный файл символы и числа записываются в виде последовательности байт.

    Для того чтобы записать данные в двоичный файл, необходимо:

      описать файловую переменную типа FAIL * с помощью оператора FILE *filename;. Здесь filename - имя переменной, где будет храниться указатель на файл.

      записать информацию в файл с помощью функции fwrite

    Для того чтобы считат ь данные из двоичного файла, необходимо:

      описать переменную типа FILE *

      открыть файл с помощью функции fopen

      закрыть файл с помощью функции fclose

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

    Для открытия файла предназначена функция fopen.

    FILE *fopen(const *filename, const char *mode)

    Здесь filename - строка, в которой хранится полное имя открываемого файла, mode - строка, определяющая режим работы с файлом; возможны следующие значения:

    «rb» - открываем двоичный файл в режиме чтения;

    «wb» - создаем двоичный файл для записи; если он существует, то его содержимое очищается;

    «ab» - создаем или открываем двоичный файл для дозаписи в конец файла;

    «rb+» - открываем существующий двоичный файл в режиме чтения и записи;

    «wb+» - открываем двоичный файл в режиме чтения и записи, существующий файл очищается;

    «ab+» - двоичный файл открывается или создается для исправления существующий информации и добавления новой в конец файла.

    Функция возвращает в файловой переменной f значение NULL в случае неудачного открытия файла. После открытия файла доступен 0-й его байт, указатель файла равен 0, значение которого по мере чтения или записи смещается на считанное (записанное) количество байт. Текущие значение указателя файла - номер байта, начиная с которого будет происходить операция чтения или записи.

    Для закрытия файла предназначена функция fclose

    int fclose(FILE *filename);

    Возвращает 0 при успешном закрытие файла и NULL в противном случае.

    Функция remove предназначена для удаления файлов.

    int remove(const char *filename);

    Эта функция удаляет с диска файл с именем filenema. Удаляемый файл должен быть закрыт. Функция возвращает ненулевое значение, если файл не удалось удалить.

    Для переименования файлов предназначена функция rename:

    int rename(const char *oldfilename, const char *newfilename);

    Первый параметр - старое имя файла, второй - новое. Возвращает 0 при удачном завершении программы.

    Чтение из двоичного файла осуществляется с помощью функции fread:

    fread(void *ptr, size, n, FILE *filename);

    Функция fread считывает из файла filename в массив ptr n элементов размера size. Функция возвращает количество считанных элементов. После чтения из файла его указатель смещается на n*size байт.

    Запись в двоичный файл осуществляется с помощью функции fwrite:

    fwrite(const void *ptr, size, n, FILE *filename);

    Функция fwrite записывает в файл filename из массива ptr n элементов размера size. Функция возвращает количество записанных элементов. После записи информации в файл указатель смещается на n*size байт.

    Для контроля достижения конца файла есть функция feof:

    int feof(FILE *filename);

    Она возвращает ненулевое значение если достигнут конец файла.

    ПРИМЕР:

    Создать двоичный файл D:\\game\\noobs.dat и записать в него целое число n и n вещественных чисел.

    #include "stdafx.h"

    #include

    using namespace std;

    int main()

    setlocale (LC_ALL, "RUS");

    int n, i;

    double a;

    //создаем двоичный файл в режиме записи

    f=fopen("D:\\game\\noobs.dat", "wb");

    // ввод числа n

    cout<<"n="; cin>>n;

    fwrite(&n, sizeof(int), 1, f);

    //цикл для ввода n вещественных чисел

    for (i=0; i

    //ввод очередного вещественного числа

    cout<<"a=";

    cin>>a;

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

    fwrite(&a, sizeof(double), 1, f);

    // закрываем файл

    fclose(f);

    system("pause");

    return 0;

    ПРИМЕР:

    Вывести на экран содержимого созданного в прошлой задаче двоичного файла D:\\game\\noobs.dat

    #include "stdafx.h"

    #include

    using namespace std;

    int main()

    setlocale (LC_ALL, "RUS");

    int n, i;

    double *a;

    FILE *f; //описываем файловую переменную

    //открываем существующий двоичный файл в режиме чтения

    //считываем из файла одно целое число в переменную n

    //вывод n на экран

    cout<<"n="<

    //выделение памяти для массива из n чисел

    a=new double[n];

    //чтение n вещественных чисел из файла в массив a

    //вывод массива на экран

    for (i=0; i

    cout<

    cout<

    // закрываем файл

    fclose(f);

    system("pause");

    return 0;

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

    int n, i;

    double a;

    FILE *f;

    f=fopen("D:\\game\\noobs.dat", "rb");

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

    fclose(f);

    f=fopen("D:\\game\\noobs.dat", "rb");

    fread(&a, sizeof(double), 1, f);

    fclose(f);

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

    int fseek(FILE *filename, long int offset, int origin);

    Функция устанавливает указатель текущий позиции файла F в соответствии со значением начала отсчета origin и смещения offset. Параметр offset равен количеству байтов, на которые будет смещен указатель файла относительно начала отсчета, заданного параметром origin. В качестве значения для параметра origin должно быть взято одно из следующих значений отсчета смещения offset, определенных в заголовке stdio.h:

    SEEK_SET - с начала файла;

    SEEK_CUR - с текущей позиции;

    SEEK_END - с конца файла.

    Функция возвращает нулевое значение при успешном выполнение операции, ненулевое - при возникновении сбоя при выполнении смещения

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

    ПРИМЕР

    В созданном раннее двоичном файле D:\\game\\noobs.dat, поменять местами наибольшее и наименьшее из вещественных чисел.

    Алгоритм решения задачи состоит из следующих этапов:

      чтение вещественных из файла в массив a.

      поиск в массиве а максимального (max) и минимального (min) значения и их номеров (imax, imin).

      перемещения указателя файла к максимальному значению и запись min.

      перемещения указателя файла к минимальному значению и запись max.

    Ниже приведен текст программы решения задачи с комментариями.

    #include "stdafx.h"

    #include

    using namespace std;

    int main()

    setlocale (LC_ALL, "RUS");

    int n, i, imax, imin;

    double *a, max, min;

    FILE *f;

    //открытие файла в режиме чтения и записи

    f=fopen("D:\\game\\noobs.dat", "rb+");

    //считываем из файла в переменную n количество

    //вещественных чисел в файле

    fread(&n, sizeof(int), 1, f);

    cout<<"n="<

    //выделяем память для хранения вещественных чисел,

    //которые будут храниться в массиве a

    a=new double[n];

    //считываем из файла в массив а вещественные числа

    fread(a, sizeof(double), n, f);

    //поиск максимального и минимального элементов

    //в массиве а и их индексов

    for (imax=imin=0, max=min=a, i=1; i

    if (a[i]>max)

    max=a[i];

    if (a[i]

    min=a[i];

    // перемещение указателя к максимальному элементу

    fseek(f, sizeof(int)+imax*sizeof(double), SEEK_SET);

    //запись min вместо максимального элемента файла

    fwrite(&min, sizeof(double), 1, f);

    // перемещение указателя к минимальному элементу

    fseek(f, sizeof(int)+imin*sizeof(double), SEEK_SET);

    //запись max вместо минимального элемента файла

    fwrite(&max, sizeof(double), 1, f);

    //закрытие файла

    fclose(f);

    //освобождение памяти

    delete [ ]a;

    system("pause");