Определение указателей
При обработке декларации любой переменной, например double x=1.5; компилятор выделяет для переменной участок памяти, размер которого определяется ее типом (double – 8 байт), и инициализирует его указанным значением (если таковое имеется). Далее все обращения в программе к переменной по имени заменяются компилятором на адрес участка памяти, в котором будет храниться значение этой переменной. Разработчик программы на языке Си имеет возможность определить собственные переменные для хранения адресов участков оперативной памяти. Такие переменные называются указателями.
Итак, указатель – это переменная, которая может содержать адрес некоторого объекта. Простейшая декларация указателя имеет формат
тип * ID_указателя;
Например: int *a; double *f; char *w;
Здесь тип может быть любым, кроме ссылки или битового поля, причем тип может быть к этому моменту только декларирован, но еще не определен (следовательно, в структуре, например, может присутствовать указатель на структуру того же типа).
Символ «звездочка» относится непосредственно к ID указателя, поэтому для того, чтобы декларировать несколько указателей, ее нужно записывать перед именем каждого из них.
Например, в декларации:
int *a, *b, с;
определены два указателя на участки памяти для целочисленных данных, а также обычная целочисленная переменная с.
Значение указателя равно первому байту участка памяти, на который он ссылается.
Указатели предназначены для хранения адресов областей памяти. В языке Cи имеются три вида указателей – указатели на объект известного типа, указатель типа void и указатель на функцию. Эти три вида различаются как своими свойствами, так и набором допустимых операций. Указатель не является самостоятельным типом данных, так как всегда связан с каким-либо конкретным типом, т.е. указатель на объект содержит адрес области памяти, в которой хранятся данные определенного типа.
Указатель типа void применяется в тех случаях, когда конкретный тип объекта, адрес которого требуется хранить, не определен (например, если в одной и той же переменной в разные моменты времени требуется хранить адреса объектов различных типов).
Указателю типа void можно присвоить значение указателя любого типа, а также сравнивать его с любыми другими указателями, но перед выполнением каких-либо действий с участком памяти, на которую он ссылается, требуется явно преобразовать его к конкретному типу.
Указатель может быть константой или переменной, а также указывать на константу или переменную.
С указателями-переменными связаны две унарные операции & и *.
Операция & означает «взять адрес» операнда. Операция * имеет смысл – «значение, расположенное по указанному адресу» (операция разадресации).
Таким образом, обращение к объектам любого типа как операндам операций в языке Cи может производиться:
– по имени (идентификатору);
– по указателю (операция косвенной адресации):
ID_указателя=&ID_объекта; – операция разыменования;
*ID_указателя – операция косвенной адресации.
Говорят, что использование указателя означает отказ от именования адресуемого им объекта.
Операция разадресации, или разыменования, предназначена для доступа к величине, адрес которой хранится в указателе. Эту операцию можно использовать как для получения, так и для изменения значения величины (если она не объявлена как константа).
Унарная операция получения адреса & применима к переменным, имеющим имя (ID), для которых выделены участки оперативной памяти. Таким образом, нельзя получить адрес скалярного выражения, неименованной константы или регистровой переменной (типа register).
Отказ от именования объектов при наличии возможности доступа по указателю приближает язык Си по гибкости отображения «объект – память» к языку ассемблера.
Пример 1:
int x, – переменная типа int ;
*y; – указатель на объект типа int;
y = &x; – y – адрес переменной x;
*y=1; – косвенная адресация указателем поля x, т.е. по
указанному адресу записать 1: x = 1.
Пример 2:
int i, j = 8, k = 5, *y;
y=&i;
*y=2; – i = 2
y=&j;
*y+=i; – j += i ® j = j+i ® j = j + 2 = 10
y=&k;
k+=*y; – k += k ® k = k + k = 10
(*y)++; – k++ ® k = k + 1 = 10 + 1 = 11
Как видно из приведенных примеров, конструкцию *ID_указателя можно использовать в левой части оператора присваивания, так как она является L-значением (см. разд. 4.3), т.е. определяет адрес участка памяти. Эту конструкцию часто считают именем переменной, на которую ссылается указатель. С ней допустимы все действия, определенные для величин соответствующего типа (если указатель инициализирован).
Пример 3:
int i1; – целая переменная;
const int i2=1; – целая константа;
int * pi1; – указатель на целую переменную;
const int * pi2; – указатель на целую константу;
int * const pi1=&i1; – указатель-константа на целую переменную;
const int * const pi2=&i2; – указатель-константа на целую константу.
Как видно из примеров, модификатор const, находящийся между ID указателя и символом «звездочка», относится к самому указателю и запрещает его изменение, a const слева от звездочки задает константное значение объекта, на который он указывает. Для инициализации указателей использована операция получения адреса &.
Указатель подчиняется общим правилам определения области действия, видимости и времени жизни.
Дата добавления: 2015-09-11; просмотров: 607;