Особенности объявлений

Инициализация указателей

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

Время жизни динамических переменных — от точки создания до конца программы или до явного освобождения памяти.

В С++ используется два способа работы с динамической памятью. Первый использует семейство функций malloc и достался в наследство от С, второй использует операции new и delete.

Существуют следующие способы инициализации указателя:

1. Присваивание указателю адреса существующего объекта:

· с помощью операции получения адреса:

int a = 5;//целая переменная

int* p = &a;//в указатель записывается адрес a

int* p (&a);//то же самое другим способом

· значения другого инициализированного указателя:

int* r = p;

· имени массива или функции, которые трактуются как адрес:

int b[10];//массив

int* t = b;// Присваивание имени массива

...

void f(int a ){ /* … */ }// Определение функции

void (*pf)(int);// Указатель на функцию

pf = f;// Присваивание имени функции

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

char* vp = (char *)0xB8000000;//шестнадцатиричная константа

3. Присваивание пустого значения:

int* suxx = NULL;

int* rulez = 0;

4. Выделение участка динамической памяти и присваивание ее адреса указателю:

· с помощью операции new:

int* n = new int;// 1

int* m = new int (10);// 2

int* q = new int [10];// 3

· с помощью функции malloc:

int* u = (int*)malloc(sizeof(int));// 4

Освобождение памяти, выделенной с помощью операции new, должно выполняться с помощью delete, а памяти, выделенной функцией malloc — посредством функции free. При этом переменная-указатель сохраняется и может инициализироваться повторно. Приведенные выше динамические переменные уничтожаются следующим образом:

delete n; delete m; delete [] q; free (u);

ВНИМАНИЕ

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

Обозначения, используемые для производных типов, достаточно трудны для понимания лишь потому, что операции * и & являются префиксными, а [] и () - постфиксными. Поэтому в задании типов, если приоритеты операций не отвечают цели, надо ставить скобки. Например, приоритет операции [] выше, чем у *, и мы имеем:

int* v[10]; // массив указателейint (*p)[10]; // указатель массива Большинство людей просто запоминает, как выглядят наиболее часто употребляемые типы. Можно описать сразу несколько имен в одном описании. Тогда оно содержит вместо одного имени список отделяемых друг от друга запятыми имен. Например, можно так описать две переменные целого типа:int x, y; // int x; int y;

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

int* p, y; // int* p; int y; НО НЕ int* y;int x, *p; // int x; int* p;int v[10], *p; // int v[10]; int* p;

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

Указатель может быть константой или переменной, а также указывать на кон­станту или переменную. Рассмотрим примеры:

 

int i: // целая переменная

const int ci = 1; // целая константа

int * pi: // указатель на целую переменную

const int * pci; // указатель на целую константу

int * const cp = &i; // указатель-константа на целую переменную

const int * const cpc = &ci; // указатель-константа на целую константу

Как видно из примеров, модификатор const, находящийся между именем указа теля и звездочкой, относится к самому указателю и запрещает его изменение a const слева от звездочки задает постоянство значения, на которое он указывает.

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

Например, в операторе

int *(*р[10] ) ( );

объявляется массив из 10 указателей на функции без параметров, возвращающих указатели на int.

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

При интерпретации сложных описаний необходимо придерживаться правила, «изнутри наружу»:

· если справа от имени имеются квадратные скобки, это массив, если скобки круглые — это функция;

· если слева есть звездочка, это указатель на проинтерпретированную ранее конструкцию;

· если справа встречается закрывающая круглая скобка, необходимо применить приведенные выше правила внутри скобок, а затем переходить наружу;

· в последнюю очередь интерпретируется спецификатор типа.

Для приведенного выше описания порядок интерпретации указан цифрами:

int * ( * p [ 10 ] ) ( ):

5 3 1 2 4 // порядок интерпретации описания

( Массив /1/ из 10 /2/ указателей /3/ на функции /4/ без параметров, возвращающих указатели на int/5/ ).