Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Комплексное пособие Си.pdf
Скачиваний:
57
Добавлен:
12.03.2015
Размер:
1.57 Mб
Скачать

}

void main(void)

{

double *py; py = Cube(5);

printf("y1 = %lf\n", *py); sin(0.7);

printf("y1 = %lf\n", *py);

}

Это происходит потому, что функция Cube() возвращает указатель на локальную переменную cube_val, которая существует только в пределах функции Cube(). После возврата из функции память, ранее распределенная под переменную cube_val, освобождается и может быть использована компилятором для других целей несмотря на то, что значение возвращенного указателя по-прежнему содержит ее адрес.

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

Данные, которые создаются, инициализируются и уничтожаются по требованию программиста называются динамическими. Для управления такими данными используются специальные стандартные функции, прототипы которых описаны в заголовочном файле <malloc.h> (для некоторых компиляторов <alloc.h>).

Для запроса динамической памяти служит функция malloc(), которая имеет следующий прототип:

void * malloc(size_t size);

Функция malloc() выделяет область динамической памяти, размером size байт, и возвращает адрес этой области памяти.

Параметр size, имеет тип size_t, который описан в файле <malloc.h> с помощью оператора typedef и используется для описания размеров, счетчиков и т.д. Обычно тип size_t соответствует типу unsigned int.

В том случае, когда функция malloc() не может удовлетворить запрос на память, она возвращает значение NULL, то есть значение не существующего указателя. Константа NULL описана в заголовочном файле <malloc.h>. Значение NULL возвращается и в том случае, когда значение параметра size нулевое.

80

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

После того, как выполнена вся работа с выделенной областью памяти, ее следует освободить с помощью функции free(), имеющей следующий прототип:

void free(void *block);

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

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

Не допускается также освобождать уже освобожденный блок памяти. Значение параметра block равное NULL не вызывает никаких действий

со стороны функции free();

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

double *A; int n;

...

n = 200;

...

A = (double *) malloc( n * sizeof(double) );

...

/* Работа с массивом A */

...

free(A);

В рассмотренном фрагменте программы выделяется память для

хранения n элементов типа double. В целях совместимости никогда не следует явно задавать размер элемента данных. Нужно пользоваться операцией sizeof(). Возвращаемое функцией malloc() значение преобразуется к типу указателя на double.

81

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

ане константами.

Внекоторых случаях бывает полезной функция calloc(), которая не только выделяет память, но и заполняет область выделенной памяти нулевыми значениями. Она имеет следующий прототип:

void * calloc(size_t nitems, size_t size);

Функция выделяет непрерывный блок памяти для nitems элементов данных размером size байт каждый и заполняет этот блок нулевыми значениями. В остальном работа ее аналогична работе функции malloc().

Функция realloc() служит для изменения размера ранее выделенного блока памяти:

void *realloc(void *block, size_t size);

Здесь block - адрес ранее выделенного блока памяти, size - новый размер блока в байтах. Функция возвращает значение нового указателя на блок памяти, которое может и не совпадать со старым.

Функция гарантирует

сохранность данных в

блоке,

разумеется,

сохранность не более size

байт. В остальном работа

функции совпадает с

работой ранее рассмотренных функций выделения памяти.

Все рассмотренные функции могут выделять память размером не более

одного сегмента,

то есть не более 64K в 16-ти разрядных моделях и не более

4G в 32-х разрядных моделях памяти.

 

 

При работе

с

динамической

памятью следует иметь в виду, что в

каждом выделенном блоке несколько байт

отводится на служебную

информацию. Так

в 16-ти разрядной Large

модели память выделяется

блоками по размеру кратными 16

байтам, и

в

каждом блоке 4 байта

служебные.

 

 

 

 

 

К сожалению,

стандартные средства работы с

динамической памятью

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

82

повышенное внимание к стратегии выделения и освобождения динамической памяти в своих программах. Иначе может получиться так, что требуемый блок памяти невозможно выделить, хотя суммарный объем неиспользуемой памяти допускает это.

Статические и динамические массивы

При объявлении массива его размер должен быть задан целочисленной константой. Если количество элементов заранее не известно, то размер выбирается в расчете на максимально возможное для конкретной задачи количество элементов, что не всегда эффективно.

Память для массива распределяется статически на этапе трансляции (до выполнения программы), такие массивы называются статическими. В явном виде в языке С можно использовать только статические массивы.

Динамические массивы можно реализовать неявно, с помощью динамического распределения памяти.

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

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

Пример создания динамического массива:

int

n;

 

 

/* указатель (ссылка)

*/

int

*m;

 

 

scanf(“%d”, &n);

sizeof(int));/* выделение памяти

*/

m =

(int

*) malloc ( n *

if (m ==

NULL) { printf(

“No memory”); return 1;}/* ошибка */

for

(int

i = 0;

i < n; i++)

 

scanf(“%d”,

&m[i]);

 

 

 

 

 

/* освобождение памяти */

 

free (m);

 

 

 

return 0;

 

 

/* успешное завершение */

 

83