netlib.narod.ru< Назад | Оглавление | Далее >

5.1. Указатели и адреса

Начнем с того, что рассмотрим упрощенную схему организации памяти. Память типичной машины представляет собой массив последовательно пронумерованных или проадресованных ячеек, которые можно обрабатывать по отдельности или связными группами. В большинстве случаев верны следующие утверждения: один байт может хранить значения типа char, двухбайтовые ячейки могут рассматриваться как целое типа short, а четырехбайтовые — как целые типа long. Указатель — это группа ячеек (как правило, две или четыре), в которых может храниться адрес. Так, если c имеет тип char, а p — указатель на c, то ситуация выглядит следующим образом:


Рис. 2

Унарная операция & выдает адрес объекта, таким образом оператор

    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< Назад | Оглавление | Далее >

Сайт управляется системой uCoz