Язык Си - руководство для начинающих.

УКАЗАТЕЛИ МАССИВОВ.

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

     Например, имя массива определяет также его первый элемент, т. е. если flizny[] - массив, то.

Flizny == &flizny[0].

И обе части равенства определяют адрес первого элемента массива. (Вспомним, что операция & выдает адрес.) Оба обозначения являются константами типа указатель, поскольку они не изменяются на протяжении всей программы. Однако их можно присваивать (как значения) переменной типа указатель и изменять значение переменной, как показано в ниже следующем примере. Посмотрите, что происходит со значением указателя, если к нему прибавить число.

/* прибавление к указателю */

Main( ).

{

Int dates[4], *pti, index;

Float bills [4], *ptf;

Pti = dates; /* присваивает адрес указателю массива */

Ptf = bills;

For(index = 0; index < 4; index++).

Printf(" указатели + %d:  %10  u  %10u \n", index, pti + index, ptf + index);

}

Вот результат:

Указатели + 0    56014    56026.

Указатели + 1     56016   56030.

Указатели + 2    56018    56034.

Указатели + 3    56020    56038.

     Первая напечатанная строка содержит начальные адреса двух массивов, а следующая строка - результат прибавления единицы к адресу и т. д. Почему так получается?

56014 + 1 = 56016? 56026 + 1 = 56030?

     Не знаете, что сказать? В нашей системе единицей адресации является байт, но тип int использует два байта, а тип float - четыре. Что произойдет, если вы скажете: "прибавить единицу к указателю?" Компилятор языка Си добавит единицу памяти. Для массивов это означает, что мы перейдем к адресу следующего элемента, а не следующего байта. Вот почему мы должны специально оговаривать тип объекта, на который ссылается указатель; одного адреса здесь недостаточно, так как машина должна знать, сколько байтов потребуется для запоминания объекта. (Это справедливо также для указателей на скалярные переменные; иными словами, при помощи операции *pt нельзя получить значение.).

Язык Си - руководство для начинающих.

РИС. 12.1. Увеличение указателя массива.

Благодаря тому что компилятор языка Си умеет это делать, мы имеем следующие равенства:

Dates + 2 == &dates[2] /* один и тот же адрес */

*(dates + 2) == dates[2] /* одно и то же значение */

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

     Между прочим, постарайтесь различать выражения *(dates + 2), и *dates + 2. Операция (*) имеет более высокий приоритет, чем +, поэтому последнее выражение означает.

(*dates) + 2:

*(dates + 2) /* значение 3-го элемента массива dates */

*dates +2    /* 2 добавляется к значению 1-го элемента массива */

Связь между массивами и указателями часто позволяет нам применять оба подхода при создании программ. Одним из примеров этого является функция с массивом в качестве аргумента.