logo search
Подбельский Фомин_Программирование на языке СИ_

Операции над указателями.

Операции над указателями. В языке Си допустимы следующие (основные) операции над указателями: присваивание; получение значения того объекта, на который ссылается указатель (синонимы: косвенная адресация, разыменование, раскрытие ссылки); получение адреса самого указателя; унарные операции изменения значения указателя; аддитивные операции и операции сравнений. Рассмотрим перечисленные операции подробнее.

Операция присваивания предполагает, что слева от знака операции присваивания помещено имя указателя, справа - указатель, уже имеющий значение, либо константа NULL, определяющая условное нулевое значение указателя, либо адрес любого объекта того же типа, что и указатель слева.

Если для имен действуют описания предыдущих примеров, то допустимы операторы:

Комментируя эти операторы, напомним, что выражение *имя_указателя позволяет получить значение, находящееся по адресу, который определяет указатель. В предыдущих примерах было определено значение переменной date (1937), затем ее адрес присвоен указателю i и указателю k, поэтому значением *k является целое 1937. Обратите внимание, что имя переменной date и разыменования *i, *k указателей i, k обеспечивают в этом примере доступ к одному и тому же участку памяти, выделенному только для переменной date. Любая из операций *k=выражение, *i=выражение, date=выражение приведет к изменению содержимого одного и того же участка в памяти ЭВМ. Иногда требуется присвоить указателю одного типа значение указателя (адрес объекта) другого типа. В этом случае используется "приведение типов", механизм которого понятен из следующего примера:

Подобно любым переменным переменная типа указатель имеет имя, собственный адрес в памяти и значение. Значение можно использовать, например, печатать или присваивать другому указателю, как это сделано в рассмотренных примерах. Адрес указателя может быть получен с помощью унарной операции &. Выражение &имя_указателя определяет, где в памяти размещен указатель. Содержимое этого участка памяти является значением указателя. Соотношение между именем, адресом и значением указателя иллюстрирует рис. 4.3.

Рис. 4.3. Имя, адрес и значение указателя

С помощью унарных операций '++' и '--' числовые (арифметические) значения переменных типа указатель меняются по-разному в зависимости от типа данных, с которыми связаны эти переменные. Если указатель связан с типом char, то при выполнении операций '++' и '--' его числовое значение изменяется на 1 (указатель z в рассмотренных примерах). Если указатель связан с типом int (указатели i, k), то операции ++i, i++, --k, k-- изменяют числовые значения указателей на 2. Указатель, связанный с типом float или long, унарными операциями '++', '--', изменяется на 4. Таким образом, при изменении указателя на единицу указатель "переходит к началу" следующего (или предыдущего) поля той длины, которая определяется типом.

Аддитивные операции по-разному применимы к указателям, точнее, имеются некоторые ограничения при их использовании. Две переменные типа указатель нельзя суммировать, однако к указателю можно прибавить целую величину. При этом вычисляемое значение зависит не только от значения прибавляемой целой величины, но и от типа объекта, с которым связан указатель. Например, если указатель относится к целочисленному объекту типа long, то прибавление к нему единицы увеличивает реальное значение на 4, т.е. выполняется "переход" к адресу следующего в памяти объекта типа long.

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

Например, после выполнения операторов

j принимает значение 4, а не 8, как можно было бы предположить исходя из того, что каждый элемент массива х[ ] занимает два байта.

В данном примере разность указателей присвоена переменной типа int. Однако тип разности указателей определяется по-разному в зависимости от особенностей компилятора. Чтобы сделать язык Си независимым от реализаций, в заголовочном файле stddef.h определено имя (название) ptrdiff_t, с помощью которого обозначается тип разности указателей в конкретной реализации.

В следующей программе используется рассмотренная возможность однозначного задания типа разности указателей. Программа будет корректно выполняться со всеми компиляторами, соответствующими стандартам языка Си.