Направления программирования. История создания языка Си. Особенности языка, страница 15

п.10.Динамическое распределение памяти. Указатели.

Динамическая память – это оперативная память (ОП) компьютера, которая предоставляется программе при ее работе. ОП представляет собой совокупность ячеек, называемых байтами, каждая из которых имеет собственный номер. Этот номер называется адресом. Он позволяет обращаться к любому байту памяти. Динамическая память – это практически единственная возможность обработки массивов данных большой размерности.

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

Средства управления динамической памятью. Указатели.

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

Синтаксис объявления:

<идентификатор типа> *<имя переменной указателя>

Пример:

int *uk;

float *f;

char *ch;

Наиболее важные операции, связанные с указателями.

- &-: операция определения адреса

- * -: операция обращения по адресу

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

Пример:

int *x,i,j;

x=&i;

*x=15;

j=*x;

Операция определения адреса возвращает адрес памяти своего операнда: <адрес>=&<переменная>.

Написание int *x приводит к тому, что компилятор резервирует память для хранения адреса переменной х, но не выделяет 2-ух байт для хранения целого числа. Для выделения 2-ух байт для хранения целого числа нужно использовать одну из функций динамического распределения памяти, например, malloc.

Файл alloc.h содержит прототипы функций динамического распределения памяти.

x=(int*) malloc(sizeof(int));

В результате выполнения оператора 1) в динамической памяти выделяется 2 байта, где можно разместить целое; 2) полученный адрес переменной указателю х. Если в памяти нет свободного места, то функция malloc возвращает 0 (NULL).

Аргумент функции malloc – количество байт, которое нужно зарезервировать. Функция возвращает указатель на тип void. Для того чтобы в данном случае функция malloc вернула в качестве результата указатель на целое, необходимо использовать явное преобразование (int*).

Способы задания указателю осмысленного значения.

1.  Использовать функцию динамического распределения памяти, например, malloc.

2.  Присвоить указателю адрес статической переменной. Поскольку память под переменную отводится в момент ее объявления, то присвоение указателю адреса переменной гарантирует, что нужная память отведена.

Пример:

int *x, i, j;

void *ptr;

x=&i;    // x-содержит адрес переменной i

*x=0;

ptr=&j;

ptr++ - недопустимо, нужно (int*)ptr++;

3.  Присвоить указателю значение указателя ранее правильно инициализированного.

Пример:

int *x, *y, i;                                                                                х            у

2

 
x=&i;

*x=2;

y=x; //y – указывает на адрес х

Замечание: Когда указателю присваивается значение другого указателя, то это значит, что одному и тому же адресу присваиваются различные имена.

Пример:

#include<stdio.h>

#include<alloc.h>

void main(void)

{

int *x=(int*)malloc(sizeof(int));                      Описание означает, что х, y, z описан как указатель на целое,

int *y=(int*)malloc(sizeof(int));                      начальное значение которого равно  адресу,  возвращаемому

int *z=(int*)malloc(sizeof(int));                      функцией malloc.