Typedef char SYMBOL; typedet unsigned UNSIGN; typedef float real;

Достаточно часто используется оператор typedefс применением структур:

typedef struct st_tag{

char name[30]; int kurs; char group[3]; int index;

} STUDENT;

Теперь для определения переменной можно использовать struct st_tag avar; или STUDENT ava;

Динамическое распределение памяти

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

СТЕК
СВОБОДНАЯ ПАМЯТЬ
РАЗДЕЛ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ И КОНСТАНТ
КОД ПРОГРАММЫ

Для глобальных переменных отводится фиксированное место в памяти на все время работы программы. Локальные переменные хранятся в стеке. Между ними находится область свободной памяти для динамического распределения. Наиболее важными функциями для динамического распределения памяти являются malloc() и free().Они используются для динамического распределения свободной памяти. Функция malloc() выделяет память, функция free() –освобождает память. Прототипы функций в stdlib.

void *malloc(size_t size); void *free(void *p);

Функция malloc()возвращает указатель типаvoid,для правильного использования значение этой функции надо преобразовать к указателю на соответствующий тип. При успешном выполнении malloc() возвращает указатель на первый байт свободной памяти требуемого размера. Если достаточного количества памяти нет, то возвращается значение 0 (нулевой указатель). Чтобы определить количество байт, необходимых для переменной, используют операцию sizeof.

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

#include <stdio.h>

#include <stdlib.h>

/* Динамическое выделение памяти */

Void main(void)

{

int *p,i;

p=malloc(100*sizeof(int)); /* под 100 цедых */

if(!p)

{

printf(“Недостаточно памяти!\n”);

Exit(1);

}

for(i=0;i<100;i++) *(p+i)=i;

for(i=0;i<100;i++) printf(“%d”, *(p++));

free(p); /* освобождение памяти */

}

В C++ используются две операции – newи delete. Их форма использования:

pointer_var = new var_type;

delete pointer_var;где

pointer_var– указатель - типа var_type;

Операция new выделяет соответствующее место для переменной в соответствующей области памяти и возвращает адрес выделенного места. Неуспешная попытка – возвращение нулевого указателя NULL.Операция delete освобождает соответствующую память, на которую указывает pointer_var.

Удобство операции new состоит в том, что операция сама определяет размер переменной var_type автоматически и возвращает указатель, уже преобразованный к этому типу.

Пример выделения памяти под массив

pointer_var = new var_type[SIZE];

delete [SIZE] pointer_var; // or delete pointer_var;

Пример использования этих операций:

#include <iostream.h>

Void main(void)

{

int *p=new int; // выделение памяти под целое

if(!p) {

cout<<”\n Недостаточно памяти!\n”;

Return 1;

}

*p=20;

cout<<p<<endl;

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

}

Пример работы с динамически выделенной памятью под массив:

#include <iostream.h>

Void main(void)

{

Unsigned int size;

cout<<”\n Введите размер массива:”;

cin>>size;

int *p=new int[size];

if(!p) {

cout<<”\n Недостаточно памяти!\n”;

Return 1;

}

for(int i=0; i<size; i++)

p[i]=i*i; // использование *p++=i*i меняет значение указателя

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

int *q=p;

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

cout<<*q++<<” “; // корректно

cout<<endl;

Delete p;

}

Динамическое выделение памяти целесообразно для выделения памяти под большие объекты, массивы, особенно под массивы неизвестного заранее размера.


Библиотеки ввода-вывода и работа с файлами в языке С

Операции ввода/вывода в языке С организованы посредством библиотечных функций. Система ввода вывода следует стандарту ANSI, называемому также буферизованным (buffered) или форматированным (formatted) вводом/выводом. Кроме того, поддерживается и другой метод ввода/вывода, так называемый UNIX-подобный, или неформатированный (не буферизованный) ввод/вывод. Язык С++ также поддерживает собственный объектно-ориентрованный ввод/вывод.

Рассмотрим понятия файл (file) и поток (stream).Система ввода/вывода языка С поддерживает интерфейс, не зависящий от того, какое в действительности используется устройство ввода/вывода, т. е. есть абстрактный уровень между программой и физическим устройством. Эта абстракция и называется потоком. Способ же хранения информации на физическом устройстве называется файлом. Несмотря на то что устройства очень разные (терминалы, диски, ленты , принтеры и т.д.), стандарт ANSI языка С связывает каждое из устройств с логическим устройством, называемым потоком. Так как потоки не зависят от физических устройств, то одна и та же функция может записывать информацию на диск, на МЛ или выводить на экран. Различаются два потока: текстовый (text) и двоичный (binary).

Текстовый поток – это последовательность символов. Двоичный поток – это последовательность байтов, которые однозначно соответствуют тому, что находится на внешнем устройстве.

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

Каждый поток, связанный с файлом, имеет управляющую структуру, называемую FILE. Она описана в заголовочном файле stdio.h.

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

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

Функция printf() имеет прототип в файле stdio.h

int printf(char *управляющая_строка,…);

управляющая строка содержит два типа информации: символы, которые непосредственно выводятся на экран, и команды формата (спецификаторы формата), определяющие, как выводить аргументы. Команда формата начинается с символа %, за которым следует код формата. Команды формата следующие:

%c – символ;

%d – целое десятичное число;

%i – целое десятичное число;

%e – десятичное число в виде x.xx e xx;

%E – десятичное число в виде x.xx E xx;

%f – десятичное число с плавающей запятой xx.xxxx;

%F – десятичное число с плавающей запятой xx.xxxx;

%g - %f или %e, что короче;

%G - %F или %E, что короче;

%o – восьмеричное число;

%u – беззнаковое десятичное число;

%x – шестнадцатеричное число (например 5a5f);

%X – шестнадцатеричное число (например 5A5F);

%% - символ %;

%p – указатель;

%n – указатель;

Другие спецификаторы:

%ld – вывод long int;

%hu – вывод short unsigned;

%Lf – вывод long double;

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

printf(“%05d”,15);дает результат 00015.

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

Выравнивание производится по правому краю поля. Если необходимо выровнять по левому знаку поля, то сразу за знаком % следует поставить знак “-“. В прототипе функции многоточием обозначен список аргументов – переменных или констант, которые следуют через запятую и подлежат выводу в соответствующем формате, следующем по порядку.

scanf() – основная функция ввода с консоли. Она предназначена для ввода данных любого встроенного типа и автоматически преобразует введенное число в заданный формат. Прототип функции из файла stdio.h имеет вид: int scanf(char *управляющая_строка, …);

Управляющая строка содержит три вида символов: спецификаторы формата, пробелы и другие символы. Команды или спецификаторы формата начинаются с символа %. Они перечислены ниже:

%c – чтение символа;

%d – чтение десятичного целого;

%i – чтение десятичного целого;

%e – чтение числа типа float;

%h – чтение числа типа short int;;

%o – чтение восьмеричного числа;

%s – чтение строки;

%x – чтение шестнадцатеричного числа;

%p – чтение указателя;

%n – чтение указателя в увеличенном формате;

Символ пробела в управляющей строке дает команду пропустить один или более символов в потоке ввода. Кроме пробела может восприниматься символ табуляции или новой строки. Нулевой символ указывает на чтение и отбрасывание (discard) этого символа. Все переменные, которые вводятся, должны указываться с помощью адресов, как положено в функциях языка С. Строка будет читаться как массив символов, и поэтому имя массива без индексов указывает адрес первого элемента.

Разделителями между двумя вводимыми числами являются символы пробела, табуляции или новой строки. Знак * после % и перед кодом формата дает команду прочитать данные указанного типа, но не присваивать это значение. Так, scanf(“%d%*c%d”,&i,&j);при вводе 50+20 присвоит переменной i значение 50, переменной j– значение 20, а символ + будет прочитан и проигнорирован.

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

scanf(“%5s”,str); указывает необходимость прочитать из потока первые 5 символов. При вводе 123456789 массив str будет содержать только 12345, остальные символы будут проигнорированы.

Если в управляющей строке встречаются какие-либо другие символы, то они предназначаются для того, чтобы определить и пропустить соответствующий символ. Поток символов 5plus10 оператором

scanf(“%dplus%d”,&i,&j);присвоит переменной iзначение 5, переменной j – значение 10, а символы plus пропустит, так как они встретились в управляющей строке.

Простейшая функция ввода getche() читает символы с клавиатуры. Функция ожидает, пока не будет нажата клавиша, и возвращает код, соответствующий символу. Одновременно происходит отображение введенного символа на экран. Прототип функции int getche(void); в conio.h.

Простейшая функция вывода – putchar(). Она выводит символ, который является ее аргументом, на экран в текущую позицию. Прототип int putchar(int c); в stdio.h.

Двумя наиболее важными аналогами функции getche() являются функции getchar() и getch().Функция getchar() производит буферизованный ввод, но требует нажатия клавиши Enter.Прототипы этих функций описаны в файле stdio.h. Функция getch() действует также, как getche(), но не выводит символ на экран, ее прототип в conio.h. Функция getch() часто используется для остановки действия программы до нажатия какой-либо клавиши именно потому, что она не выдает эхо на экран.

Функции gets() и puts() осуществляют соответственно ввод и вывод на консоль строки символов. Прототип gets() имеет вид char gets(chat *s);здесь s – указатель на массив символов, который заполняется вводимыми с клавиатуры символами. Окончание ввода осуществляется нажатием клавиши Enter. Заносится символ “\0”, завершающий строку.

Функция puts() выводит на экран строку. Ее прототип int puts(char *s);

Эта функция, так же как и printf(), распознает специальные символы. В отличие от printf() функция puts() может выводить только строку, зато работает быстрее и ее запись короче, чем у printf(). В результате действия функции puts() всегда происходит переход на новую строку. Если вывод успешно завершен, то функция возвращает ненулевое значение, в противном случае возвращает символ EOF. Прототипы функций puts() и gets() находятся в файле stdio.h.

Указатель на файловую переменную

Связующим звеном между файлом и потоком в системе ввода-вывода стандарта ANSI языка С, является указатель на файл (file pointer). Указатель на файл – это указатель на информацию, которая определяет различные стороны файла: имя, статус, текущую позицию. Указатель файла определяет имя файла и его использование в потоке, ассоциированном с ним. Указатель файла – это указатель на структуру типа FILE вstdio.h. В файле stdio.h определены также следующие функции.

Функция Действие функции
fopen() Открыть файл
fclose() Закрыть файл
fputc() Записать символ в поток
fgetc() Прочитать символ из потока
fputs() Записать строку символов в поток
fgets() Прочитать строку символов из потока
fseek() Изменить указатель позиции файла на указанное место
fprintf() Форматная запись в файл
fscanf() Форматное чтение из файла
feof() Возвращает значение “истинно”, если достигнут конец файла.
ferror() Возвращает значение “ложно”, если обнаружена ошибка
fread() Читает блок данных из потока
fwrite() Пишет блок данных в поток
rewind() Устанавливает указатель позиции файла на начало
remove() Уничтожает файл

Чтобы объявить указатель на файл, используется оператор FILE *fput;

Функция fopen() выполняет два действия: во-первых, открывает поток и связывает файл с этим потоком; во-вторых, возвращает указатель, ассоциированный с этим файлом. Прототип функции

FILE *fopen(char *filename, char *mode);где mode– это строка, содержащая режим открываемого файла. Возможные режимы открытия файлов перечислены ниже:

Режим Действие
“r” Открыть для чтения
“w” Создать для записи
“a” Открыть для добавления в существующий файл
“rb”,”rt” Открыть двоичный (текстовый) файл для чтения
“wb”,”wt” Открыть двоичный (текстовый) файл для записи
“ab”,”at” Открыть двоичный (текстовый) файл для добавления
“r+” Открыть файл для чтения и записи
“w+” Создать файл для чтения и записи
“a+” Открыть для добавления или создать для чтения и записи
“r+b”,”r+t” Открыть двоичный (текстовый) файл для чтения и записи
“w+b”,”w+t” Создать двоичный (текстовый) файл для чтения и записи
“a+b”,”a+t” Открыть двоичный (текстовый) файл для добавления или создать для чтения и записи

Если требуется открыть файл с именем test для записи, то достаточно написать

FILE *fp;

fp=fopen(“test”,”w”);

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

FILE *fp;

if(fp=fopen(“test”,”w”))==NULL)

{

puts(“Не могу открыть файл \n”);

Exit(1);

}

Этот метод определяет ошибку при открытии файла. Константа NULLопределена в stdio.h. Функция exit() имеет прототип в void exit(int val);Она прекращает выполнение программы, а величину valвозвращает в вызывающую программу. При этом перед прекращением работы программы закрывает все открытые файлы, освобождает буферы, в частности выводя все необходимые сообщения на экран.

Запись символа производится функцией fputc() с прототипом int fputc(int ch, FILE *fptr);Если операция была успешной, то возвращается записанный символ, в случае ошибки возвращается EOF.

Функция fgetc() считывает символ из потока, открытого функцией fopen(). Прототип функции

int getc(FILE *fptr);В функциях fputc(), fgetc() используется только младший байт.

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

ch=getc(fptr);

while(ch!=EOF)

{

ch=fgetc(fptr);

}

Запись строки символов в поток производится функциейfputs()с прототипом

int fputs(char *, FILE *fptr);.

Чтение строки символов из потока производится функциейfgets()с прототипом

char *fgets(char *s, int n, FILE *fptr); где n –количество символов.

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

Функции fprintf(),fscanf() имеют прототипы в файле stdio.h

int fprintf(FILE *fptr, char *управляющая_строка,…);

int fscanf(FILE *fptr, char *управляющая_строка,…);

Для определения конца файла служит функция feof() с прототипом int feof(FILE *fptr);

Функция возвращает значение “истинно”, если конец файла достигнут, и “ложно” в противном случае. Далее конструкция читает файл до конца.

while(!feof(fptr))

{

ch=fgetc(fptr);

}

Функция fclose() служит для закрытия файла. Ее прототип: int fclose(FILE *fptr); При успешном закрытия файла соответствующие данные считываются из (в) файл, происходит освобождение блока управления файлом, ассоциированного с потоком, и файл становится не доступным.

Если произошла ошибка чтения или записи файла, то соответствующая функция возвращает EOF. Чтобы определить, что же в действительности произошло, служит функция ferror() с прототипом: int ferror(FILE *fptr);,которая возвращает значение “истинно” при успешной выполнении последней операции с файлами и “ложно” в противном случае. Функция ferror() должна быть выполнена непосредственно после каждой операции с файлами, иначе ее сообщение об ошибке будет потеряно.

Функция rewind() устанавливает указатель позиции файла на начало файла, определенного как аргумент функции. Прототип функции имеет вид: void rewind(FILE *fptr);

Функции fread(), fwrite() используются для чтения и записи блоков данных;

unsigned fread(void *buf, int bytes, int c,FILE *fptr);

unsigned fwrite(void *buf, int bytes, int c,FILE *fptr);

гдеbuf– указатель на область памяти, откуда происходит обмен информацией;

с – сколько единиц записей, каждая длиной bytes байтов будет считано (записано);

bytes –длина каждой единицы записи в байтах;

fptr– указатель на соответствующий файл.

Чтение и запись в файл необязательно делать последовательно, можно это делать непосредственно доступом к нужному элементу файла посредством функции fseek(), которая устанавливает указатель позиции файла в нужное место. Прототип функции:

int fseek(FILE *fptr, long numbytes, int origin);

fptr –указатель на соответствующий файл;

numbytes – количество байт от точки отсчета для установки текущей позиции указателя файла;

origin – один из макросов, определенных в stdio.h.

Точка отсчета Макрос Значение
Начало файла SEEK_SET
Текущая позиция SEEK_CUR
Конец файла SEEK_END

 

Когда начинается выполнение программы, автоматически открывается 5 предопределенных потоков. Первые три из них – стандартный ввод (stdin), стандартный вывод (stdout) и стандартный поток ошибок (stderr) В обычной ситуации они связаны с консолью, однако они могут быть перенаправлены на другой поток. Можно использовать stdin, stdout, stderr как указатели файлов во всех функциях, применяющих тип FILE. Кроме того, есть два потока stdprnи stdaux, ассоциированные соответственно с принтером и последовательным портом ПК. Эти потоки открываются и закрываются автоматически.

Функци remove() уничтожает указанный файл. Прототип функции int remove(char *filename);

Так как язык С связан с ОС UNIX, то существует вторая система ввода-вывода. Эта система соответствует стандарту UNIX. Прототипы функций в файле io.h. Этими функциями являются:

read() – читает буфер данных;

write() – пишет в буфер данных;

open() – открывает файл;

close() – закрывает файл;

lseek() – поиск определенного байта в файле;

unlink() – уничтожает файл.

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

#include<iostream.h>

#include<conio.h>

#include<string.h>

#include<stdio.h>

Int main()

{

char *tmp=new char[80];

char *fname=new char[20];

char *word=new char[80];

char *ptr;

FILE *fr;

FILE *fw;

Clrscr();

fw=fopen("bbb.cpp","w");

int a=0;

cout<<"Give name file:"<<endl;

Do

{

Cin.getline(fname,20);

if ((fr=fopen(fname,"r"))==NULL)

{

a=0;

cout<<"Invalid name file!! Give correct name:"<<endl;

}

else a=1;

} while(a==0);

cout<<"\nGive word:";

Cin.getline(word,80);

while(!feof(fr))

{

// fscanf(fr,"%s",tmp); // read only to space

Fgets(tmp,80,fr);

if ((ptr=strstr(tmp,word))!=NULL) // search word

{

cout<<tmp<<endl;

fprintf(fw,"%s",tmp);

}

}

Fclose(fr);

Fclose(fw);

Getch();

Return 0;

}

 

 

Работа с файлами в C++

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

Пример

Ifstream input_from;

Ofstream out;

Fstream in_out_stream;

Если поток уже создан, то он может быть ассоциирован с файлом с помощью функцииopen().Ее прототип

void open(char *filename, int mode, int access);

filename –имя файла;

mode – режим, определяющий как открыт файл;

access– режим доступа файла. Режимы доступа приведены в таблице (режимы могут комбинироваться)

Режим Тип Макрос
Открытый доступ NORMAL
Только для чтения READ_ONLY
Скрытый файл HIDDEN
Системный файл SYSTEM
Архивный файл ARCHIVE

Значения режима открытия файла определены через следующие величины, находящиеся в файле fstream.h. (режимы могут комбинироваться)

Режим Назначение
ios::app Файл открыт в режиме добавления
ios::ate Маркер позиции файла установлен на конец файла
ios::in Открыть файл для ввода
ios::nocreate Если файл не существует, то не создавать новый
ios::out Файл открыт для вывода
ios::trunc Если файл уже существует - он очищается, маркер – в начале файла
ios::noreplace Прекратить выполнение, если файл уже существует
ios::text Текстовый файл
ios::binary Двоичный файл

В случае объявления потока ifstream или ofstreamавтоматически устанавливаются соответственно режимы ios::in и ios::out.

При вызове функции open()указывать все параметры необязательно. Например, вызовы

Ofstream out;

out.open(“myfile”,ios::out,0);

и вызовы

Ofstream out;

out.open(“myfile”);

эквивалентны.

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

Fstream m_in_out;

m_in_out.open(“myfile”,ios::in|ios::out);

Для закрытия файла используется функция close().Пример m_in_out.close();

Пример открытия файла для вывода:

Ofstream m_out;

m_out.open(“myfile”,ios::out,0);

if(!m_out)

{

cout<<”Не могу открыть файл”;

Return 1;

}