записи
&a[i] и
a+i также будут эквивалентными, т. е. и в том и в другом случае это адрес
i-го элемента после
a. С другой стороны, если
pa - указатель, то его можно использовать с индексом, т. е. запись
pa[i] эквивалентна записи
*(pa+i). Короче говоря, элемент массива можно изображать как в виде указателя со смещением, так и в виде имени массива с индексом.
Между именем массива и указателем, выступающим в роли имени массива, существует одно различие. Указатель - это переменная, поэтому можно написать pa=a или pa++. Но имя массива не является переменной, и записи вроде a=pa или a++ не допускаются.
Если имя массива передается функции, то последняя получает в качестве аргумента адрес его начального элемента. Внутри вызываемой функции этот аргумент является локальной переменной, содержащей адрес. Мы можем воспользоваться отмеченным фактом и написать еще одну версию функции strlen, вычисляющей длину строки.
>/* strlen: возвращает длину строки */
>int strlen(char *s)
>{
> int n;
> for (n = 0; *s!= '\0'; s++)
> n++;
> return n;
>}
Так как переменная s - указатель, к ней применима операция ++; s++ не оказывает никакого влияния на строку символов функции, которая обратилась к strlen. Просто увеличивается на 1 некоторая копия указателя, находящаяся в личном пользовании функции strlen. Это значит, что все вызовы, такие как:
>strlen("3дравствуй, мир"); /* строковая константа */
>strlen(array); /* char array[100]; */
>strlen(ptr); /* char *ptr; */
правомерны.
Формальные параметры
>char s[];
и
>char *s;
в определении функции эквивалентны. Мы отдаем предпочтение последнему варианту, поскольку он более явно сообщает, что s есть указатель. Если функции в качестве аргумента передается имя массива, то она может рассматривать его так, как ей удобно - либо как имя массива, либо как указатель, и поступать с ним соответственно. Она может даже использовать оба вида записи, если это покажется уместным и понятным.
Функции можно передать часть массива, для этого аргумент должен указывать на начало подмассива. Например, если a - массив, то в записях
>f(&a[2])
или
>f(a+2)
функции f передается адрес подмассива, начинающегося с элемента a[2]. Внутри функции f описание параметров может выглядеть как
>f(int arr[]) {…}
или
>f(int *arr) {…}
Следовательно, для f тот факт, что параметр указывает на часть массива, а не на весь массив, не имеет значения.
Если есть уверенность, что элементы массива существуют, то возможно индексирование и в "обратную" сторону по отношению к нулевому элементу; выражения p[-1], p[-2] и т.д. не противоречат синтаксису языка и обращаются к элементам, стоящим непосредственно перед