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

§ 2. Инициализация и присваивание указателей

Переменную-указатель можно также проинициализировать, используя ранее определённую переменную-указатель. Корректным будет следующее объявление: int* q=p; что равносильно int *q; q=p; (а не *q=p;). После этого q и p будут содержать один и тот же адрес, адрес ячейки t. Поэтому *p и *q —это одно и то же целочисленное значение t. Заметим, что присваивания *q=p; *p=q; q=*p; p=*q; p=t; q=t; некорректны. Объяснить, почему.

Нельзя переменную-указатель проинициализировать константой или определённым ранее значением переменной.

a) int *p=1000; /* Ошибка!!! */

b) int *p; p=1000; /* Ошибка!!! */

c) int *p, k; cin>>k; p=k; /* Ошибка!!!. */

Это связано с тем, что система сама должна “найти” свободную ячейку и её адрес присвоить нашей переменной. Наша “помощь” будет отвергнута. Переменную-указатель нельзя также вводить. Поэтому cin>>p; недопустимо.

Не будет ошибкой, если во время объявления указателя мы его не проинициализируем. Но до его первого использования надо не забыть это сделать, например, с помощью присваивания: float f=1.1, *p1, *p2; … p1=&f; … p2=p1;

cout<<(*p1)<<” “<<(*p2); В результате будет выведено дважды одно и то же число 1.1, если, конечно, значение f, или, что то же самое, *p1 или *p2 не меняли.

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

double x=12.34, y; int *w; w=&x; y=*w; printf (“%f”, y); // Ошибка!!!

не приведёт к желаемому результату 12.34. Во время компиляции w=&x; появится сообщение об ошибке, связанное с несоответствием типов. Но если int* w; заменить на double * w, то программа выведет 12.34.

§ 3. Распределение динамической памяти

    1. Операция new

Операция new — один из способов определения значения переменной указателя. Ее синтаксис такой: указатель = new имя_типа; Например, если объявлен указатель float *p; то операция p=new float; выполняет следующее:

1. Выделяет и делает доступным свободный участок динамической памяти, размер которого соответствует типу данных, определяемому именем типа (в примере 4 байта для размещения вещественного числа).

2. Кроме этого, в случае успешного выполнения операция new возвращает адрес начала выделенного участка. В примере значение этого адреса присваивается переменной-указателю (переменной p).

Но значение выделенной ячейки, которое в программе обозначается *p, после выполнения этой операции ещё не определено. Поэтому cout<<(*p) выведет случайное число. Для задания значения *p надо выполнить, например, ввод cin >> (*p); или использовать другой способ (присваивание, получение с помощью функции и т. п.). Обратим внимание, что речь идёт об определении *p, а не p. Поэтому напомним, что cin>>p; или p=1.1; ошибочны.

Если участок нужных размеров не может быть “найден”, то операция new возвращает нулевое (точнее, неопределённое) значение адреса. Оно обозначается в программе константой NULL, которая записывается обязательно большими буквами. Тогда в программе после p=new float; желательно записать:

if (p==NULL) // или if (!p)

{ cout<<”\nError”; getch(); exit(0);}.

Как нулевое числовое значение, так и значение NULL для указателей равносильно false в операциях сравнения.

Стандартная функция exit(0) прекращает выполнение всего проекта. Она более “сильная” по сравнению с оператором return, так как осущетвляет выход не только из функции, где записана, а останавливает работу всего проекта. Заметим, что самым “слабым” в этой группе является оператор break, который прерывает всего лишь цикл или оператор выбора switch, продолжая выполнение функции, если цикл или switch не были последними в ней.

С помощью рассматриваемой операции new можно проинициализировать не только значение указателя, но и задать значение выделенной ячейки памяти. В таком случае операция применяется так: указатель = new имя_типа(значение);. Например, p=new float(3.1); определяет как значение указателя p, так и значение *p. Это равносильно p=new float; *p=3.1; Заметим, что значение записывается в круглых, а не в квадратных скобках. Квадратные скобки будем позже использовать для создания динамического массива. Но динамический массив так инициализировать нельзя! (см. следующую главу). Доступ к переменной, адрес которой находится в p, выполняется операцией “*” (разыменование). Поэтому cout<<p<<” “ <<(*p); выведет шестнадцатеричный адрес и число 3.1.