Использование указателей на структуры позволяет использовать весьма сложно организованные данные типа различного рода списков, очередей и деревьев. Рассмотрим так называемые линейные списки.
Линейный список - это упорядоченная структура данных, каждый элемент которой содержит ссылку (указатель), связывающую его со следующим элементом.
Для организации списков служат структуры, состоящие из двух смысловых частей: основной, содержащей полезную информацию, и дополнительной, содержащей ссылку на следующий элемент списка. Графически это можно представить следующим образом:
В виде списков удобно представлять большие объемы информации, размер которых заранее неизвестен.
Рассмотрим, например, как можно было бы организовать хранение информации о товарах для программы "магазин".
typedef struct _GOODS{
char name[21];
int number;
float price;
struct _GOODS *next;
} GOODS;
Очевидно, программа должна иметь переменную - указатель на первый элемент списка. Последний элемент списка отличается тем, что в поле next имеет константу NULL - то есть пустой указатель. Тогда список может быть представлен так:
......... ......... ......... ...........
TOP : : : : : : : : : : :NULL:
......... ......... ......... ...........
Программа формирования списка товаров выглядит следующим образом:
GOODS *new_GOODS ( void)
{
GOODS *p;
p = (GOODS* ) malloc( sizeof(GOODS) );
if (p==NULL) {printf("Недостаточно памяти\n");
exit(1);}
return p;
}
GOODS *in_goods( void )
{
GOODS *top, *q;
printf("Введите характеристики товаров в виде:\n" \
"наименование количество цена\n" \
"-------окончание ввода \"end\"-------\n");
top = NULL;
while (1)
{
q = new_GOODS(); if( !in_goods1(q) ) { free(q);
return top; }
q->next = top; top = q;
}
}
Обращение к этой программе будет выглядеть так:
top = in_goods();
Вспомогательная программа new_GOODS осуществляет все необходимые действия по выделению памяти и контролю за ее наличием.
Достоинство такой организации данных в том, что используется ровно столько памяти, сколько надо (накладные расходы - поле адреса). Вместе с тем список может быть сколь угодно большим. Ограничение - память ЭВМ. Недостаток - мы не имеем возможности прямого доступа к памяти.
Рассмотрим процедуру вывода на печать содержимого списка. Обратить внимание на то, что содержимое выводится в порядке обратном вводу (в принципе можно было бы и наоборот).
Головная функция должна выглядеть следующим образом:
void main( void )
{
GOODS *top;
top = in_goods();
out_goods ( top );
}
Как же быть с сортировкой, а ее вообще не надо делать, так как можно в процессе ввода получить отсортированный список, вставляя очередную запись в нужное место.
Рассмотрим вспомогательную задачу: необходимо вставить запись, на которую указывает указатель g в список за записью, на которую указывает указатель p.
g .........
: :. :
......|..
2 ^ | 1
| V
TOP ......... ......... ......... ......... ..........