- •Глава 7. Указатели
- •Основные понятия
- •Объявление указателей
- •Операция адреса
- •Операция разыменования
- •Инициализация указателей
- •Адресная арифметика
- •Функции и указатели
- •Передача аргументов в функцию по указателю
- •Указатель в качестве возвращаемого значения функции
- •Некоторые особенности использования указателей Нулевые указатели
- •Указатели на тип void
- •Указатели на константу и константные указатели
Указатель в качестве возвращаемого значения функции
Функции могут не только принимать указатели в качестве аргументов, но и возвращать их.
Чтобы вернуть указатель, функция должна объявить его тип в качестве типа возвращаемого значения. Например, int* fun(); – объявление функции, которая должна вернуть указатель на целое число.
Если функция возвращает указатель, то значение, используемое в её операторе return, также должно быть указателем (как и для всех функций, return-значение должно быть совместимым с типом возвращаемого значения).
// Пример 7.3. Функция возвращает указатель.
// Передача аргументов в функцию по указателю.
#include<iostream>
using namespace std;
int* fun(int*, int*);
int main(){
int a = 2, b = 7, * p;
p = fun(&a, &b);
cout<<*p<<endl;
system("pause");
}
int* fun(int* x, int* y){
if(*x > *y)return x; else return y;
}
// Пример 7.5. Функция возвращает указатель.
// Передача аргументов в функцию по значению.
#include<iostream>
using namespace std;
int* fun(int, int);
int main(){
int a = 2, b = 1, *p;
p = fun(a, b); cout<<*p<<endl;
system("pause");
}
int* fun(int x, int y){
int * t;
if(x > y) t = &x; else t = &y;
return t;
}
Некоторые особенности использования указателей Нулевые указатели
Нулевой указатель – это указатель, который в данный момент не адресует никакого достоверного значения в памяти. Значение нулевого указателя равно нулю – единственный адрес, к которому нет доступа.
Указателю можно присвоить нулевой адрес следующим оператором:
int *p = 0;
Существует стандартная описанная во многих заголовочных файлах константа NULL, обозначающая нулевой адрес. Таким образом, предыдущему оператору равносилен следующий оператор:
int *p = NULL;
Присваивание нулевого значения указателю является инициализацией и может защитить программу от ошибок, вызванных использованием неинициализированных указателей.
Как и другие глобальные переменные, глобальные указатели инициализируются значениями, равными нулю, во всех остальных случаях требуется явная инициализация, например, int *p = &c;
Часто при программировании используются проверки вида
if(p != NULL) оператор; // выполняется оператор, если
// p адресует достоверные данные
if(!p) оператор; // равнозначная запись
Указатели на тип void
В языке С++ можно встретить также указатели типа void, которые указывают на неопределённый тип данных:
void * vp;
Указателю на void можно присвоить адрес данного любого типа, но указатель на void нельзя разыменовать, пока он не приведён к какому-либо конкретному типу, так как неизвестно, на какой объём памяти он указывает:
void *p; double f = 12.34;
p = &f; cout<<*(double*)p<<endl; // 12.34
Не следует путать нулевой указатель и указатель на тип void. Нулевой указатель не адресует достоверных данных, а указатель на void адресует данные неопределённого типа и также может быть нулевым.
Указатель на void нельзя разыменовать, пока он не приведён к конкретному типу
Указатели на константу и константные указатели
При объявлении указателей, как и обычных переменных, может использоваться спецификатор const. Например, в следующих операторах
int x = 15, k = 10; const int * p = &x;
наличие спецификатора const означает, что указатель содержит адрес константы, следовательно, значение, находящееся по данному адресу, меняться не может, т.е. при выполнении оператора *p = 7;
компилятором будет выдано сообщение об ошибке. Но в этом случае возможно выполнение оператора p = &k;
Если же спецификатор const стоит между символом * и именем указателя, то сам указатель является константой:
int x = 15, k=10; int* const p = &x;
При этом можно выполнить оператор *p = 7;, но p = &k; – нельзя (компилятором будет выдано сообщение об ошибке).
Если же в объявлении будет два спецификатора const, как например, в следующих операторах
int x = 15, k = 10; const int* const p = &x;
то нельзя будет изменить ни сам указатель, ни значение, находящееся по адресу в нем.
// Пример 7.4. Использование сonst-указателя и указателя на сonst.
#include<iostream>
using namespace std;
int main(){
int x = 333; int y = 777;
// const_указатели
// должны быть проиницилизированы сразу при объявлении!
int * const px = &x;
*px = 999; // можно
// px = &y; // !!!! нельзя
const int *py; py = &y; // укзатель на сonst
py = &x; // можно
// *py = 111; !!!! нельзя
*(int*)py = 555; // можно! Приведение типа к (int*) необходимо,
// чтобы избавиться от указателя на константу
system("pause");
}