Предположим, что надо создать массив структур, размер которого выясняется только во
время работы программы. Для этого надо
1) объявить переменную типа указатель на нужный тип данных;
2) выделить память с помощью оператора new и запомнить адрес выделенного блока;
3) использовать новую область как обычный массив.
Book *B;
int n;
printf("Сколько у вас книг? ");
scanf ("%d", &n); // вводим размер массива
B = new Book[n]; // выделяем память
// здесь работаем с массивом B, как обычно
Delete B; // освобождаем память
Иногда требуется выделить в памяти одну структуру. При этом мы получаем ее адрес, который записываем в переменную-указатель. Как получить доступ к полю структуры?
Один из вариантов – «разыменовать» указатель, то есть обратиться к той структуре, на
которую он указывает. Если p – указатель на структуру типа Book, то обратиться к ее полю author можно как (*p).author. Эта запись означает «мне нужно поле author той структуры, на которую указывает указатель p».
В языке Си существует и другой способ обратиться к полю структуры: можно написать и
|
|
p->author, что значит то же самое, что и (*p).author, но более понятно. В следующем
примере динамически выделяется память на 1 структуру, ее поля считываются с клавиатуры, изатем структура записывается в конец текстового файла books.txt.
Book *p;
FILE *fp;
p = new Book; // выделить память на 1 структуру
printf("Автор "); // ввод полей через указатель
gets (p->author);
printf("Названиекниги ");
gets (p->title);
printf("Год издания, кол-во страниц ");
scanf("%d%d", &p->year, &p->pages);
fp = fopen("books.txt", "a"); // дописать в конец файла
fprintf("%s\n%s\n%d %d\n", // обращение через указатель
p->author, p->title, p->year, p->pages);
fclose (fp);
Delete p; // освободить память
Структуры как параметры процедур
Структуры, так же, как и любые другие типы, могут быть параметрами функций и процедур. В этом разделе будут показаны три способа передачи структур в процедуры и функции иописаны их отличия. Рассмотрим процедуру, которая записывает в поле year (год изданиякниги) значение 2009.
Передача по значению
Если параметр процедуры объявлен как:
Void Year2009(Book b)
{
b.year = 2009;
}
Main()
{
Book b;
Year2009 (b);
}
то при работе процедуры создается КОПИЯ этой структуры в стеке (специальной области памяти, где хранятся параметры и локальные переменные процедур и функций) и процедура работает с этой копией. Такой подход имеет два недостатка:
1) во-первых, процедура не изменяет поля структуры в вызывающей программе; это значит, что в нашем случае задача решается неверно;
2) во-вторых, самое главное – структуры могут быть достаточно больших размеров, и создание новой копии может привести к нехватке места в стеке, где создаются локальные
|
|
переменные.
Передача по ссылке
Поэтому чаще всего параметры-структуры передаются в процедуры и функции по
ссылке (при объявлении за именем типа структуры ставят знак &).
void Year2009(Book &b)
{
b.year = 2009;
}
В этом случае фактически в процедуру передается адрес структуры и процедура работает с темже экземпляром, что и вызывающая программа. При этом все изменения, сделанные в процедуре, остаются в силе. Работа со структурой-параметром внутри процедуры и вызов этой процедуры из основной программы никак не отличаются от предыдущего варианта.
Передача по адресу
Передача по ссылке возможна только при использовании языка Си++ (она не входит в
стандарт языка Си). Тем не менее, в классическом Си можно передать в качестве параметра адрес структуры. При этом обращаться к полям структуры внутри процедуры надо через оператор ->.
void Year2009(Book *b) // параметр – адрес структуры
{
b->year = 2009; // обращение по адресу (через указатель)
}
Main()
{
Book b;
Year2009 (&b); // передается адрес структуры
}
Сортировка по ключу
Поскольку в структуры входит много полей, возникает вопрос: а как их сортировать? Это
зависит от конкретной задачи, но существуют общие принципы, о которых мы и будем говорить.Для сортировки выбирается одно из полей структуры, оно называется ключевым полем или просто ключом. Структуры расставляются в определенном порядке по значению ключевогополя, содержимое всех остальных полей игнорируется.И еще одна проблема – при сортировке элементы массива меняются местами. Структурымогут быть достаточно больших размеров, и копирование этих структур будет занимать оченьмного времени. ПоэтомуСортировку массива структур обычно выполняют по указателям.
Мы уже использовали этот прием для сортировки массива символьных строк. В памяти формируется массив указателей p, и сначала они указывают на структуры в порядке расположенияих в массиве, то есть указатель p[i] указывает на структуру с номером i. Затем остается только расставить указатели так, чтобы ключевые поля соответствующих структур были отсортированы в заданном порядке. Для решения задачи удобно объявить новый тип данных PBook –
указатель на структуру Book .
typedef Book *PBook;
Пример ниже показывает сортировку массива структур по году выпуска книг. Основной алгоритм сортировки массива указателей заложен в процедуру SortYear, которая имеет два параметра – массив указателей и число структур. Здесь используется «метод пузырька».
void SortYear (PBook p[], int n)
{
int i, j;