Функции для манипулирования динамической памятью в стандарте Си следующие:
void *calloc(unsignedn, unsignedsize); – выделение памяти для размещения n объектов размером size байт и заполнение полученной области нулями; возвращает указатель на выделенную область памяти;
void *malloc (unsignedn) – выделение области памяти для размещения блока размером n байт; возвращает указатель на выделенную область памяти;
void *realloc (void *b, unsignedn) – изменение размера размещенного по адресу b блока на новое значение n и копирование (при необходимости) содержимого блока; возвращает указатель на перераспределенную область памяти; при возникновении ошибки, например, нехватке памяти, эти функции возвращают значение NULL, что означает отсутствие адреса (нулевой адрес);
coreleft (void) – получение размера свободной памяти в байтах только для MS DOS (используется в Borland C++), тип результата: unsigned – для моделей памяти tiny, small и medium; unsigned long – для моделей памяти compact, large и huge;
voidfree (void *b) – освобождение блока памяти, адресуемого указателем b.
Для использования этих функций требуется подключить к программе в зависимости от среды программирования заголовочный файл alloc.h или malloc.h.
В языке Си размерность массива при объявлении должна задаваться константным выражением.
Если до выполнения программы неизвестно, сколько понадобится элементов массива, нужно использовать динамические массивы, т.е. при необходимости работы с массивами переменной размерности вместо массива достаточно объявить указатель требуемого типа и присвоить ему адрес свободной области памяти (захватить память).
Память под такие массивы выделяется с помощью функций mallос и calloc (операцией new) во время выполнения программы. Адрес начала массива хранится в переменной-указателе. Например:
В примере значение переменной n задано, но может быть получено и программным путем.
Обнуления памяти при ее выделении не происходит. Инициализировать динамический массив при декларации нельзя.
Обращение к элементу динамического массива осуществляется так же, как и к элементу обычного – например а[3]. Можно обратиться к элементу массива и через косвенную адресацию – *(а + 3). В любом случае происходят те же действия, которые выполняются при обращении к элементу массива, декларированного обычным образом.
После работы захваченную под динамический массив память необходимо освободить, для нашего примера free(b);
Таким образом, время жизни динамического массива, как и любой динамической переменной – с момента выделения памяти до момента ее освобождения. Область действия элементов массива зависит от места декларации указателя, через который производится работа с его элементами. Область действия и время жизни указателей подчиняются общим правилам для остальных объектов программы.
Пример работы с динамическим массивом:
#include <alloc.h>
void main()
{
double *x;
int n;
printf("\nВведите размер массива – ");
scanf("%d", &n);
if ((x = (double*)calloc(n, sizeof(*x)))==NULL) { // Захват памяти
Напомним, что ID двухмерного массива – указатель на указатель. На рис. 10.1 приведена схема расположения элементов, причем в данном случае сначала выделяется память на указатели, расположенные последовательно друг за другом, а затем каждому из них выделяется соответствующий участок памяти под элементы.
. . .
int **m, n1, n2, i, j;
puts(" Введите размеры массива (строк, столбцов): ");
scanf(“%d%d”, &n1, &n2);
// Захват памяти для указателей – А (n1=3)
m = (int**)calloc(n1, sizeof(int*));
for (i=0; i<n1; i++) // Захват памяти для элементов – B (n2=4)
*(m+i) = (int*)calloc(n2, sizeof(int));
for ( i=0; i<n1; i++)
for ( j=0; j<n2; j++)
m[i] [j] = i+j; // *(*(m+i)+j) = i+j;
. . .
for(i=0; i<n; i++) free(m[i]); // Освобождение памяти