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

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), в которой сегменты программы и данных занимают одну и ту же область памяти, то вы подвергаете себя риску испортить свой же загрузочный модуль. Поэтому старайтесь не рубить сук, на котором вы сами же сидите и внимательно пишите программы, использующие указатели.