Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка-ТП-С++.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
661.5 Кб
Скачать

5.1.1. Динамическое распределение

Изменим еще раз нашу программу:

#include <alloc.h>

void main()

{

int *iptr;

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

*iptr = 421;

printf("Содержимое iptr; %p\n", iptr);

printf("Адресуемое значение: %d\n", *iptr);

}

Эта версия позволяет вполне обойтись без описания переменной ivar, которое непременно фигурировало в предыдущих примерах. Вместо адреса этой переменной iptr присваивается значение (тоже адрес некоторой ячейки памяти), возвращаемое некоторой функцией, которая называется malloc, и описана в библиотеке alloc.h (отсюда появление директивы #include в начале программы). Затем по этому адресу присваивается значение 421 и переменная *iptr вновь, как и в предыдущем примере, принимает значение 421.

Обратите внимание, что если вы теперь выполните программу, то получите иное значение iptr, чем раньше, но значение *iptr останется равным 421.

Разберем теперь, что же делает оператор

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

Разобьем его на три части:

– выражение sizeof(int) возвращает количество байтов, требуемое для хранения переменной типа int; для компилятора С++, работающего на IBM PC, это возвращаемое значение равно 2;

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

– выражение (int*) указывает, что этот начальный адрес суть указатель на данные типа int. Выражение такого вида известно как выражение приведения типа (type casting).

В данном случае С++ не требует обязательного его применения. Но в связи с тем, что для других компиляторов С++ это выражение является обязательным, при его отсутствии вы получите сообщение об ошибке:

Non-portable pointer assignment.

(“Непереносимое в другие системы присваивание указателя.”)

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

Наконец, адрес, полученный с помощью функции malloc, запоминается в iptr. Таким образом, вами получена динамически созданная целая переменная к которой вы можете обращаться при помощи идентификатора *iptr.

Весь этот блок можно описать следующим образом: “выделить в памяти компьютера некоторый участок для переменной типа int, затем присвоить начальный адрес этого участка переменной iptr, являющейся указателем на переменную типа int”.

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

Иными словами, не присваивайте целое значение *iptr без предварительного присвоения адреса в iptr.

5.1.2. Указатели и функции

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

Рассмотрим, например, следующую функцию:

void swap(int *a, int *b)

{

int temp;

temp = *a; *a = *b; *b =temp;

}

Эта функция swap (обмен) объявляет два формальных параметра a и b, как указатели на некие данные типа int. Это означает, что функция swap работает с адресами целых переменных (а не с их значениями). Поэтому будут обработаны данные, адреса которых переданы функции во время обращения к ней.

Далее представлена программа, вызывающая swap:

void main()

{

int i, j;

I = 421;

j = 53;

printf("До обращения: i=%4d, j=%4d\n", i, j);

swap(&i, &j);

printf("После обращения: i =%4d, j=%4d\n", i, j);

}

Вы видите, что эта программа действительно заменяет значение i на значение j (переставляет их местами). Заменим эту программу на аналогичную ей, раскрыв процедуру swap в теле программы:

void main()

{

int i, j;

int *a, *b, temp;

i = 421;

j = 53;

printf("До обработки: i = %4d j = %4d\n", i, j);

a = &i;

b = &I;

temp = *a; *a = *b; *b = temp;

printf("После обработки: I = %4d j = %4d\n",

i, j);

}

Эта программа, конечно, приводит к тому же результату, что и предыдущая, поскольку не отличается от нее. При вызове функции swap(&i, &j); значения двух фактических параметров (&i, &j) присваиваются двум формальным параметрам (a и b), обрабатываемым непосредственно операторами функции swap.