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

5.1.3. Адресная арифметика

Каким образом вам необходимо поступить, если вы хотите так модифицировать программу, чтобы iptr указывала на три переменных типа int вместо одной? Далее представлено одно из возможных решений:

#include <alloc.h>

void main()

{

#define NUMINTS 3

int *list, i;

list = (int*)calloc(NUMINTS, sizeof(int));

*list = 421;

*(list+1) = 53;

*(list+2) = 1806;

printf("Список адресов:");

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

printf("%4p ", (list + i));

printf("\nСписок значений: ");

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

printf("%4p ", *(list + i));

printf("\n");

}

Вместо функции malloc эта программа использует функцию calloc с двумя параметрами: первый показывает, для скольких элементов будет происходить резервирование памяти, второй – величину каждого элемента в байтах. После обращения к функции calloc, list указывает на участок памяти размером 6 (3*2) байта, достаточный для хранения переменных типа int.

Более подробно рассмотрим следующие три оператора. Первый оператор вам знаком – *list = 421;. Он означает: “запомнить 421 в переменной типа int, расположенной по адресу, хранящемуся в переменной list”.

Следующий *(list + 1) = 53; – особенно важен для понимания. На первый взгляд, его можно интерпретировать так: “запомнить 53 в переменной типа int, расположенной байтом дальше адреса, хранящегося в list”. Если это так, то вы окажетесь в середине предыдущей int-переменной (которая имеет длину 2 байта). Это, естественно, испортит ее значение.

Однако, ваш компилятор с С++ не сделает такой ошибки. Он “понимает”, что list – это указатель на тип int, и поэтому выражение list + 1 представляет собой адрес байта, определенного выражением list + (1*sizeof(int)), и, поэтому, значение 53 не испортит значения 421 (т.е. для этого значения будет выделена другая ячейка памяти).

Аналогично, (list + 2) = 1806; представляет адрес байта list + (2*sizeof(int)) и 1806 запоминается, не затрагивая два предыдущих значения.

В общем, ptr + i представляет адрес памяти, определяемый выражением ptr + (i*sizeof(int)).

Введите и выполните вышеописанную программу; на выходе вы получите следующее:

Список адресов: 066A 06AC 06AE

Список значений: 421 53 1806

Заметьте, что адреса различаются не на один байт, а на два, и все три значения хранятся отдельно.

Подведем итог. Если вы используете ptr, указатель на тип type, то выражение (ptr + 1) представляет адрес памяти (ptr + (1*sizeof(type)), где sizeof(type) возвращает количество байт, занимаемых переменной типа type.

5.1.4. Неправильное употребление указателей

Использование указателей может быть наиболее трудно для понимания начинающему программисту на С++. Когда надо использовать указатели, а когда нет? Когда использовать косвенный оператор (*)? Когда использовать адресный оператор (&)? И как избежать ошибок операционной системы во время выполнения программы?

На все эти и многие другие вопросы ответ будет дан ниже.

5.1.5. Использование неинициализированных указателей

Одна серьезная опасность таится в присвоении значения по адресу, содержащемуся в указателе, без первоначального присвоения адреса этому указателю.

Например:

void main()

{

int *iptr;

*iptr = 421;

printf("*iptr = %d\n", *iptr);

}

Эта ловушка опасна тем, что программа, содержащая ее, может быть “верна” и компилятор может не выдать никаких сообщений во время компиляции такой программы. В примере, указанном выше, указатель iptr имеет некоторый произвольный адрес, по которому запоминается значение 421. Эта программа настолько мала, что шанс что-нибудь затереть в памяти с ее помощью ничтожно мал, однако в больших программах возрастает вероятность разрушения других данных, поскольку вполне возможно, что по адресу iptr уже хранится другая информация. Если вы используете модель самой маленькой памяти (tiny), в которой сегменты программы и данных занимают одну и ту же область памяти, то вы подвергаете себя риску испортить свой же загрузочный модуль. Поэтому старайтесь не рубить сук, на котором вы сами же сидите и внимательно пишите программы, использующие указатели.