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

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

время работы программы. Для этого надо

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;


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: