Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование 07

.pdf
Скачиваний:
8
Добавлен:
26.03.2015
Размер:
252.21 Кб
Скачать

Указатели и массивы

Соответственно: a[1] = 5;

эквивалентно

*(pa + 1) = 5;

Или:

pa+i - это адрес элемента a[i],

*(pa + i) — это значение эллемента a[i].

Сказанное выше справедливо для любого массива из любого количества элементов.

Смысл добавления единицы к указателю состоит в том, pa+1 указывает на следующий элемент массива, а pa+i

— на i-тый.

15.10.13

Указатели и массивы

Между обращением а массиву по индексам и адресной арифметикой существует самое близкое родство.

По определению, значение переменной и выражения типа «массив» является адресом нулевого элемента массива (начала массива).

Поэтому

pa = &a[0];

эквивалентно pa = a;

15.10.13

Указатели и массивы

На самом деле вычисляя выражение a[i] компиялтор сам преобразует его к форме

*(a + 1),

поскольку эти две формы тождественны.

Применяя к обеим частям тождества операцию взятия адреса, получим что &a[i] и a+i — это

одно и тоже, то есть адрес i-го элемента после a. В свою очередь если pa — указатель, его можно употреблять в выражениях с индексом:

pa[i] будет идентично *(pa + i).

15.10.13

Указатели и массивы

Выражение в виде обращения к массиву по индексу эквивалентно обращению к указателю со смещением!

Однако есть и одно различие — указатель это переменная, поэтому выражения типа pa = a и pa++ разрешены, но

конструкции типа a = pa или a++ нет.

15.10.13

Указатели и массивы

Если в функцию передаётся имя массива, то по сути туда поступает адрес первого элемента.

Имя массива в аргументах функции — это указатель, то есть переменная, содержащая адрес.

Когда функции принимают в качестве аргументов массив, то следующие две формы записи в аргументах эквивалентны:

char s[]; char *s;

15.10.13

Указатели и массивы

В качестве примера напишем функцию, определяющую длину строки:

/*int strlen(char s[]) - тоже правильно */ int strlen(char *s)

{

int n;

for (n = 0; *s != '\0'; s++) n++;

return n;

}

15.10.13

Указатели и массивы

Кроме того, в функцию можно передавать не весь массив, а только требуемую часть:

func(&a[3]);

А ещё к указателям,так как они являются переменными, можно применять операцию инкремента и декремента (pa++, pa--) - для

получения адреса следующего и предыдущего элемента и индексировать в обратном направлении (pa[-1], pa[-2]).

Но помните что в С нет контроля границ массивов!

15.10.13

Адресная арифметика

Кроме того, с указателями можно выполнять следующие операции:

Сравнивать между собой с помощью операций сравнения (==, !=, <, >, >=, <=);

Складывать и вычитать с целыми числами и друг с другом.

Присваивать значение 0 (NULL) или сравнивать с ним.

Присваивать значения указателей одного типа.

Для присваивания значений указателей разных указателей нужно явное приведение типов.

Без приведения можно присваивать только указатель на void*

15.10.13

Адресная арифметика

Значение указателя NULL говорит о том, что он никуда не указывает.

Указатели типа void * могут ссылаться на любой тип, также указатели этого типа можно присваивать указателям любых других типов без приведения (но не в С++).

Кроме того с указателями типа void * нельзя производить операции инкремент и декремент и ссылаться по смещению.

Указатели типа void * это мощный механизм обобщённого программирования, с их помощью реализуются многие обобщённые структуры данных, т. н. коллекции.

15.10.13

Адресная арифметика

Вот ещё один пример функции возвращающей длину строки:

int strlen(char *s)

{

char *p =

s;

while (*p

!= '\0')

p++;

 

return p -

s;

}

15.10.13