netlib.narod.ru | < Назад | Оглавление | Далее > |
Начнем с того, что рассмотрим упрощенную схему организации памяти. Память типичной машины представляет собой массив последовательно пронумерованных или проадресованных ячеек, которые можно обрабатывать по отдельности или связными группами. В большинстве случаев верны следующие утверждения: один байт может хранить значения типа char, двухбайтовые ячейки могут рассматриваться как целое типа short, а четырехбайтовые — как целые типа long. Указатель — это группа ячеек (как правило, две или четыре), в которых может храниться адрес. Так, если c имеет тип char, а p — указатель на c, то ситуация выглядит следующим образом:
Унарная операция & выдает адрес объекта, таким образом оператор
p = &c;
присваивает переменной p адрес ячейки памяти, в которой хранится значение c (говорят, что p указывает на c). Операция & применяется только к объектам, расположенным в памяти: к переменным и элементам массивов. Ее операндом не может быть ни выражение, ни константа, ни регистровая переменная.
Унарная операция * называется операцией косвенного доступа. Примененная к указателю она выдает объект, на который данный указатель указывает. Предположим, что x и y имеют тип int, а ip — указатель на int. Следующие несколько строк придуманы специально для того, чтобы показать, каким образом объявляются указатели и как используются операции & и *.
int x = 1, y = 2, z[10]; int *ip; /* ip - указатель на int */ ip = &x; /* теперь ip указывает на x */ y = *ip; /* y теперь равен 1 */ *ip = 0; /* x теперь равен 0 */ ip = &z[0]; /* ip теперь указывает на z[0] */
Объявления x, y и z нам уже знакомы. Объявление указателя ip
int *ip;
является мнемоническим — оно говорит что выражение *ip имеет тип int. Синтаксис объявления переменной «подстраивается» под синтаксис выражений, в которых эта переменная может встретиться. Указанный принцип применим и в объявлениях функций. Например, запись
double *dp, atof (char *);
означает, что выражения *dp и atof(s) имеют тип double, а аргумент функции atof является указателем на char.
Вы, наверное, заметили, что указателю разрешено указывать только на объекты определенного типа. (Существует одно исключение: «указатель на void», который может указывать на объекты любого типа, но к такому указателю нельзя применять операцию косвенного доступа. Мы вернемся к этому в параграфе 5.11.)
Если ip указывает на переменную x типа int, то *ip можно использовать в любом месте, где допустимо применение x, например,
*ip = *ip + 10;
увеличивает *ip (то есть x) на 10.
Унарные операции * и & имеют более высокий приоритет, чем арифметические операции, так что присваивание
y = *ip + 1;
берет объект, на который указывает ip, и добавляет к нему 1, а результат присваивает переменной y. Аналогично
*ip += 1;
увеличивает на единицу объект, на который указывает ip; те же действия выполняют выражения
++*ip
и
(*ip)++
В последней записи скобки необходимы, поскольку если их не будет, увеличится значение самого указателя, а не то, на что он указывает. Это обусловлено тем, что унарные операции * и ++ имеют одинаковый приоритет и выполняются справа налево.
И наконец, так как указатели сами являются переменными, в тексте они могут встречаться и без операции косвенного доступа. Например, если iq это еще один указатель на int, то выражение
iq = ip
копирует содержимое ip в iq, чтобы ip и iq указывали на один и тот же объект.
netlib.narod.ru | < Назад | Оглавление | Далее > |