Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(л0)Переменные_указатели_ссылки_функции.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
538.11 Кб
Скачать

1.5. Обращение к элементам массива

Последний важный момент рассмотренного кода в том, как преобразуется обращение к элементу массива. Имя массива — это указатель на его начало. Индекс, переданный в квадратных скобках, — смещение относительно начала массива (именно поэтому первый элемент массива имеет номер 0).

Конструкция arr[i] будет преобразована компилятором к *(arr + i). К начальному адресу массива будет прибавлено число с учетом размерности типа данных. А затем будет взято значение по вычисленному адресу.

1.6. Приведение типов при работе с указателями

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

char c[10];

char* pc = c;

int* pi = pc;

Компилятор языка C даст предупреждение, а компилятор C++ эту операцию считает не безопасной, поэтому выдает ошибку: указатели указывают на разные типы данных. Устранить неоднозначность может только программист, выполнив приведение типов:

int* pi = (int*)pc;

для компилятора с++ чаще встречается другой форма записи с аналогичным действием:

int* pi = reinterpret_cast<int*>(pc);

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

1.7. Работа с динамическими переменными

До настоящего момента в рассмотренных примерах мы рассматривали указатели, которые указывали на уже существующие переменные. Но очень часто указатели используются для работы с динамическими переменными – переменными, которые могут создаваться и уничтожаться в процессе работы программы.

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

Рассмотрим следующий пример:

int *pV;

*pV = 10;

С точки зрения компилятора все корректно: pV – это указатель на ячейку памяти, предназначенную для хранения значения типа int, 10 – это целое.

Но мы объявили не инициализированный указатель, это значит, что адрес, хранящийся в указателе pV, может указывать на случайную ячейку памяти (в том числе и на ту, которая может быть занята другой переменной).

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

Для того чтобы указанная операция была выполнена корректна, необходимо выполнить дополнительную операцию:

pV = new int;

*pV = 10;

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

Важно помнить, что память под переменные, выделенные оператором new, не освобождается автоматически. Если программист только выделяет память и не освобождает ее после завершения использования, то имеет место «утечка памяти», она опасна в случае долго работающих программ или программ, работающих с большими объемами данных. Поэтому память, выделенная при помощи new, должна быть освобождена при помощи delete:

delete pV;

1. 8. Основные выводы:

int x; //объявление переменной целого типа

int* p; //объявление указателя на переменную целого типа

p = &x; //присвоить p адрес переменной x

x = *p; //присвоить x значение, которое находится по адресу, сохраненному в p

2. Применение указателей при работе с функциями

2.1. Передача параметров по значению

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

int summ(double a, double b)

{

return a + b;

}

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

#include <iostream>

using std::cout;

using std::endl;

void swap(int a, int b)

{

int temp = a;

a = b;

b = temp;

}

int main()

{

int x = 10, y = 20;

int* p;

cout<<"value x = "<< x<<" value y = "<< y<<endl<<endl;

cout<<"call swap(x, y);"<<endl<<endl;

swap(x, y);

cout<<"value x = "<< x<<" value y = "<< y<<endl<<endl;

return 0;

}

Если выполнить функцию, передав в нее x и y, окажется, что никакого обмена не произошло.

При вызове этой функции формальные параметры a и b получат копии значений фактических параметров x и у (с которыми функция была вызвана).