
Программирование 07
.pdf
Указатели и массивы
Соответственно: 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