Использование неинициализированных указателей
При изменении значений указателя не производится никакого контроля за тем, чтобы новый адрес памяти был легально выделен программе. Так, записав последовательность операторов
int *pv = new int;
…
pv++;
*pv=1;
изменитсям содержимое области памяти, которая либо не была выделена, либо была выделена для совершенно других целей! Поэтому следует соблюдать особую осторожность при изменении значений указателей.
При записи выражений с указателями следует обращать внимание на приоритет операций и при необходимости расставлять скобки. Так, выражение (*p)++ увеличивает значение, расположенное по адресу, хранящемуся в p. С другой стороны, выражение *(p++) изменяет значение указателя. Тем не менее, оба выражения возвращают старые данные, хранящиеся по старому адресу. Поэтому, записывая оператор *p++, задумайтесь – поймет ли компилятор то, что вы хотели сказать!
(*p++выполняется в C++ как *(p++))
Константные указатели
В C++ они подразделяются на два типа:
- указатели, значение которых не изменяется в ходе выполнения программы. Они описываются, например, так:
int a;
int * const p=&a;
В этом случае значение p не может быть изменено, и операторp++вызовет ошибку;
- указатели, хранящие адрес константы. Они описываются следующим образом:
int a;
const int *p=&a;
В этом случае ошибку компиляции вызовет оператор (*p)++.
С другой стороны, оператор a++ считается вполне нормальным.
Динамическое выделение памяти
Выделение динамической памяти для переменной типа int можно выполнить двумя способами:
a) с помощью функции malloc, описанной еще в языке C:
int *pi=(int*)malloc(sizeof(int));
(функция malloc возвращает значение типа
void *, и необходимо выполнить преобразование типа)
b) с помощью появившейся в C++ операции new:
int *pi = new int;
Освобождение памяти соответственно:
free(pi);
delete pi;
После освобождения памяти значение указателя не изменяется!!!
Проблемы, возникающие при работе с указателями
Неинициализированный указатель содержит какое-то значение, которое трактуется как адрес памяти. Если случайно окажется, что этот адрес доступен для приложения – последствия непредсказуемы!
2. Использование “зависших” указателей
После освобождения динамической памяти ее адрес остается доступным в программе. Обращение по такому адресу приведет либо к разрушению динамической памяти, либо к доступу к повторно выделенной памяти.
3. “Утечка” памяти
Потеря значения адреса выделенной памяти влечет невозможность доступа к ней (в том числе и освобождения) до окончания работы программы.