Между указателями и массивами существует сильная взаимосвязь. Любое действие над элементами массива может быть выполнено при помощи указателей, т.е. если известны индексы элементов массива. Точно так же можно работать и со значениями этих элементов, расположенных по конкретным адресам в ОП, что возможно только при использовании указателей. Любую программу, выполняющую действия с массивами, можно написать только с использованием указателей. При этом вариант программы с указателями будет работать быстрее.
Ранее при определении массивов было сказано, что они представляют собой совокупность элементов, каждый из которых имеет одни и те же атрибуты. Таким образом, все характеристики массива полностью определялись при его объявлении и не могли меняться в течение выполнения программы, поэтому такие массивы будем называть статическими.
При объявлении статического массива:
<тип_элементов_массива> <имя_массива> [<количество_элементов>];
<имя_массива> становится указателем на нулевой байт области памяти, выделяемой для размещения элементов массива, т.е. <имя_массива> будет содержать адрес первого элемента массива. <количество_элементов>– константное выражение, а <тип_элементов_массива> четко определяет размеры памяти, выделяемой для каждого элемента массива.
Таким образом, количество элементов массива и размеры памяти, выделяемой для него, однозначно задаются при объявлении массива. Однако при решении многих задач необходимо, чтобы память для массива выделялась в процессе выполнения программы, т.е. потребности в памяти заранее не известны и не могут быть определены при объявлении массива.
Массив называется динамическим, если количество его элементов заранее не известно или может изменяться в процессе выполнения программы. При работе с динамическими массивами обязательно выделение и освобождение выделенной динамической памяти. Динамической памятью (кучей) называется участок ОП, где размещаются данные, необходимые для работы программы.
Схему решения задач с использованием динамических массивов можно описать следующим образом. Динамический массив объявляется как указатель на некоторый тип данных, затем запрашивается, сколько элементов будет содержать массив (или это число вычисляется). Затем при помощи функции выделения динамической памяти необходимо выделить нужный объем ОП из кучи и нулевой адрес выделенной динамической памяти присвоить объявленному ранее указателю. После этого происходит некоторая обработка элементов массива (решается задача). Если динамический массив будет не нужен для дальнейшего решения задачи, выделенная под него динамическая память освобождается при помощи функции освобождения динамической памяти.
Рассмотрим библиотечные функции выделения и освобождения динамической памяти. Функции malloc(), calloc(), realloc() динамически выделяют память в соответствии со значениями параметров и возвращают адрес нулевого байта выделенного участка памяти. Для универсальности тип возвращаемого значения каждой из этих функций есть void*. Указатель такого типа можно преобразовать к указателю любого типа с помощью операции приведения типа (<имя типа данных> *).
Функция free() освобождает память, выделенную перед этим с помощью одной из трех функций malloc(), calloc(), realloc(). Сведения о выделенном участке памяти передаются в функцию free() с помощью указателя. Функции работы с динамической памятью приведены в табл6.
Таблица 6 | |
Функция | Форма обращения к функции и её краткое описание |
malloc | p = (<тип_данных>*)malloc(n); p – указатель на <тип_данных>; n – переменная типа unsigned int Указатель p получает адрес нулевого байта выделенной динамической памяти размера в n байт При неудачном завершении возвращает значение NULL |
calloc | p = (<тип_данных> *)calloc(n, m); p – указатель на <тип_данных>; n и m – переменные типа unsigned int Указатель p получает адрес нулевого байта выделенной динамической памяти, необходимой для размещения n элементов по m байт каждый При неудачном завершении возвращает значение NULL |
realloc | p = (<тип_данных> *)realloc(pred_p, n); p – указатель на <тип_данных>; n – переменная типа unsigned int; pred_p – указатель на <тип_данных> содержит адрес нулевого байта изменяемого блока Указатель p получает адрес нулевого байта ранее выделенной области динамической памяти и изменяет размеры этой области до n байт. Если pred_p равен NULL (память не выделялась), то функция выполняется как malloc() |
free | free(p); p – указатель на <тип_данных>, адресующий ранее выделенный участок динамической памяти. Функция освобождает участок (блок) динамической памяти, адрес нулевого байта содержится в переменной p |
При использовании данных функций необходимо подключать головной файл stdlib.h.