Организация данных в виде стека. Понятие стека ("магазина"): первый пришел, последний ушел. LIFO (LAST IN FIRST OUT) Описание стека как списка: typedef struct _LIST { info_t info; /* тип данных для информации */ struct _LIST *next; } LIST; В вызывающей функции стек должен быть описан так: LIST *head = NULL; /* голова списка */ Действия со стеком определяется несколькими функциями: 1. Помещение элемента в стек (в голову списка) void add_head (LIST *head, info_t a) { LIST *t; if (t=(LIST*) malloc (sizeof (LIST))) { t->info = a; /* 1 */ t->next = (*head); /* 2 */ (*head) = t; /* 3 */ } } t .......... 2 : 1 a : : .......... ......... ......... .......... 3 : : : : : : : :NULL: ......... ......... .......... head 3 2. Извлечение из стека (из головы списка) info_t get_head (LIST *head) { LIST *t; info_t a; if ( *head) { a = (*head)->info; /* 1 */ t = (*head); /* 2 */ (*head) = (*head)->next; /* 3 */ free (t); } return a; } t 2 .......... ......... .......... : 1 a : : : : : : :NULL: .......... ......... .......... head 3 Организация данных в виде очереди. Понятие очереди: первый пришел, первый ушел. FIFO (FIRST IN FIRST OUT). Описание очереди: такое же, что и стека, но надо хранить и начало и хвост очереди. .......... ......... .......... head : : : : : : : :NULL: .......... ......... .......... tail Тогда в вызывающей программе очередь описывается так: LIST *head = NULL, *tail = NULL; Помещение элемента в очередь (в хвост списка): 1-ый элемент: head 3 .......... : :NULL: 5 .......... tail t Остальные: ......... ......... ......... : : : : : : : : : ......... ......... ......... head 5 4 tail ........... 5 :1 a:NULL: ........... t 2 void add_tail (LIST*head, LIST*tail, info_t a) { LIST*t; if (t = (LIST*) malloc (sizeof (LIST))) { t->info = a; /* 1 */ t->next = NULL; /* 2 */ if (*head) == NULL) (*head) = t; /* 3 */ else (*tail)->next = t;/* 4 */ (*tail) = t; /* 5 */ } } Организация данных в виде деревьев. Схематически данные в виде дерева можно представить в следующем виде: root . . . . . . . . root ..................... : : : : ..................... .................. ............ : : : : : : : : .................. ............ ........... .......... .......... .......... : : :0: : :0:0: : :0:0: : :0:0: ........... .......... .......... .......... .............. : :0 :0 : .............. Каждая вершина дерева представляет собой структуру, имеющую информационное поле и указатели поддеревья, исходящие из этой вершины. Максимальное количество поддеревьев, сходящихся в одной вершине, называется порядком дерева. В данном случае порядок дерева равен двум, т. е. изображено бинарное дерево. Описать это дерево можно следующим образом: typedef struct _NODE { info_t info; struct _NODE*left; struct _NODE*right; } NODE; . . . NODE *tree = NULL; При организации работы с деревом программист с помощью функции malloc получает необходимые вершины дерева и, заполняя поля left и right, организует необходимые связи вершины дерева. Библиотека ввода-вывода языка C. Прототипы функций описаны в файле <stdio.h>. Основные идеи: 1. В C отсутствуют встроенные средства ввода-вывода. Весь ввод-вывод осуществляется через функции, находящеся в библиотеке и легко замещаемые. 2. Каждый файл рассматривается как непрерывный поток байт (stream). Никакой внутренней структуры файла не поддерживается. 3. Не делается никаких различий между файлами на дисках и на других внешних устройствах. Открытие потока. Перед работой с любым файлом его надо предворительно открыть, т. е. связать с некоторой структурой предопределенного типа FILE, в которой находится вся необходимая информация для работы с потоком. Открытие потока осуществляется с помощью функции fopen, которая в случае успешного завершения возвращает указатель на структуру типа FILE, а в случае аварии - NULL. Полный ее прототип: FILE *fopen (const char *filename, const char *mode); где, filename - строка символов, содержащая имя файла (полное или простое), записанное по правилам DOS; mode - режим работы файла, тоже строка символов; mode = "r" - открыть существующий файл для чтения; "w" - создать файл для записи, информация из существующего файла теряется; "a" - открытие для записи в конец существующего файла или создание для записи, если файла нет; "r+" - открытие существующего файла для чтения и записи; "w+" - создание нового файла для чтения и записи; "a+" - откратие или создание для обновления в конец; Закрытие потока. После того как была выполнени вся работа с файлом, его необходимо закрыть. Это необходимо сделать по крайней мере по двум причинам: 1. если программа обрабатывает большое количество файлов, то в конце концов может не хватить на все системных ресурсов; 2. незакрытый файл может в случае сбоя пропасть. Файл закрывается функцией: int fclose (FILE *stream); где, stream - указатель потока. Функция возвращает 0 в случае успеха и EOF - если нет. EOF - (End Of File) - специальная константа из <stdio.h>. Функция fcloseall закрывает все потоки: int fcloseall (void); В случае успеха функция возвратит количество закрытых потоков, иначе - EOF. Если программист забыл закрыть какие-либо потоки, то все равно они будут закрыты системой MS DOS по завершению работы программы. Типичный пример работы с файлом: <stdio.h> . . . void main (void) { FILE *my_file; static char *fn = "d:\\USER\\f.dat"; . . . if ((my_file = fopen (fn, "r")) == NULL) { printf ("Не могу открыть файл %s\n", fn); return; } . . . fclose (my_file); } |