Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информатика 1.docx
Скачиваний:
11
Добавлен:
26.09.2019
Размер:
364.88 Кб
Скачать

Функция realloc

Функция void* realloc(void *block, size_t size); перераспределяет уже выделенный блок памяти, на который указывает параметр block, сжимая или увеличивая его размер до значения, передаваемого в параметре size.

Функция realloc пытается сжать или увеличить предварительно выделенный блок до размера в size байт. Аргумент block указывает на блок памяти, полученный при вызове функций malloc, calloc или realloc. Если block является нулевым указателем, realloc работает также как и malloc.

При уменьшении размера блока, realloc (с помощью менеджера памяти) обычно просто уменьшает его размер в таблице распределения памяти, не перемещая сам блок в памяти. При увеличении размера блока памяти, если это возможно без перемещения его в памяти, realloc просто выделяет дополнительную память сразу за блоком и присоединяет его (с помощью менеджера памяти) к этому блоку. Если же такое увеличение невозможно, то realloc выделяет новый блок памяти размером size, копирует туда содержимое старого блока, после чего освобождает старый блок.

Функция realloc возвращает адрес блока, который может отличаться от исходного. Если блок не может быть выделен или size равно 0, то realloc возвращает NULL.

Пример:

#include <alloc.h>

void main()

{

long *pl;

int i;

//Выделяем память под динамический массив.

pl=malloc(10*sizeof(long));

if(pl)

{

// память выделена, можем с ней работать

for(i=0;i<10;i++)

pl[i]=i*2;

// Теперь нам необходимо увеличить размер массива

pl=realloc(pl,20);

if(pl)

{

//Работаем с увеличенным массивом.

// Старые значения сохранились, дополним их новыми.

for(i=10;i<20;i++)

pl[i]=i*2+1;

}

else

{

// В данном случае память не освобождаем, т.к.

// она была уже освобождена в функции realloc,

// после чего realloc вышла с ошибкой, не выделив

// память заново.

return;

}

// В конце работы освобождаем память,

// на которую указывает pl

free(pl);

}

else

{

printf("Недостаточно памяти\n");

}

}

  1. Передача аргументов в функцию с помощью указателей. Передача массива в функцию.

Передача массивов в качестве аргументов функции.

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

func1(int *ai);

func2(int ai[5]);

func3(int ai[]);

void main()

{

int ai[5]

func1(ai);

func2(ai);

func3(ai);

}

В этом примере показаны три основных формы передачи массива в функцию – в виде указателя, и в виде параметра массива. Для одномерных массивов все 3 формы записи полностью идентичны. Во всех трёх случаях в функции будет передаваться указатель на начало области памяти, где хранятся элементы массива, и внутри функций работа с ними будет происходить по всем правилам работы с указателями. При использовании формы записи с квадратными скобками, значение внутри скобок опускается.

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

void func(int *ai)

{

int i=2,j=5;

int element;

// нам необходимо взять элемент [i][j] из массива ai

element=ai[i*6+j];

}

void main()

{

int i[5][6];

func(i);

}

Эта работа может быть облегчена, если передавать двумерный массив в виде параметра-массива. В этом случае параметр всё равно представляет собой указатель (он всё так же является локальной переменной-указателем, под которую статически выделяется память), но к ней становятся применимы правила адресной арифметики массивов.

Так, если функция объявлена в виде

void func(int ai[5][6]);

то одинарная операция индексации, применённая к переменной ai, будет возвращать не элемент одномерного массива (как это было в предыдущем случае, когда передача массива осуществлялась в виде обычного указателя), а будет возвращать указатель на начало соответствующей строки двумерного массива. Поэтому для извлечения элемента из двумерного параметра-массива можно просто дважды применить операцию индексации: ai[i][j]. При этом компилятор будет автоматически перерассчитывать двумерную индексацию в одномерную по формуле из прошлого примера: i*6+j.

Как видим, в этой формуле не участвует количество элементов в самом старшем измерении, поэтому в объявлении параметров функции его можно опустить и записать:

void func(int ai[][6]);

То же самое верно и для массивов-параметров большей размерности.

Таким образом, предыдущий пример можно переписать в следующем виде:

void func(int ai[5][6])

{

int i=2,j=5;

int element;

// нам необходимо взять элемент [i][j] из массива ai

element=ai[i][j];

}

void main()

{

int i[5][6];

func(i);

}

В качестве небольшого вывода ещё раз обращу внимание на тот факт, что в отличие от передачи параметров простых типов, при работе с параметрами-массивами мы всегда имеем дело с указателями. Это немаловажное обстоятельство позволяет непосредственно из вызываемой функции изменять значения объектов, определённых в вызывающей функции.