Указатели
1. Адреса и указатели
2. Операции над указателями
3. Применение указателей
166.50K
Category: programmingprogramming

Адреса и указатели

1. Указатели

2. 1. Адреса и указатели

3.

Указатель – это переменная, значением которой является адрес
объекта конкретного типа.
Если в некоторый момент времени адрес объекта неизвестен
или переменная – указатель еще не получила значения, то
такой переменной придается значение специальной
константы NULL, не равное никакому адресу («нулевой»
адрес).
Указатели, как и любые переменные программы, должны быть
объявлены. В объявление указателя входит указание типа
объекта, на который ссылается указатель, признак (символ *)
того, что переменная является указателем, имя указателя.

4.

Примеры объявления указателей:
int *f; /*указатель на объект целого типа*/
float *a,*b; /*указатели на объекты вещественного типа*/
1.Обычный указатель (кроме указателя типа void) может
ссылаться на объекты только того типа, который указан при
объявлении.
2. После объявления значение указателя не определено
(соответствует NULL).
Получение адресной информации осуществляется с помощью
унарной операции &. Например, адрес переменной "А"
формируется на основе выражения

Это выражение в ходе выполнения программы позволяет
определить адрес участка памяти, выделенного
переменной А.

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

6.

Применительно к указателям в языке Си допустимы операции:
1. Присваивание;
2. Разыменование;
3. Унарные операции сложения и вычитания;
4. Аддитивные операции;
5. Операции сравнения;
6. Получение адреса самого указателя.

7.

Операция присваивания
Предполагает, что справа от знака присваивания стоит:
1. Другой указатель, который имеет конкретное значение;
2. Константа NULL;
3. Адрес объекта того же типа, что и указатель слева.
Примеры записи операции присваивания:
с=d;
Предполагается, что переменные с и d являются указателями одного
типа. После этой операции оба указателя обеспечивают доступ к
одному участку памяти.
c=NULL;
c=&a; //Указателю присваивается значение адреса
Если указателю одного типа требуется присвоить значение указателя
другого типа, то применяют приведение типов:
int *k;
float *z;
k=(int) z; //преобразование перед присваиванием

8.

Операция разыменования (обращения по адресу, раскрытия
ссылки)
1. Позволяет обратиться к соответствующему объекту
(переменной). Эта операция является унарной.
2. Операция разыменования обозначается символом
звездочки. Выражение *f соответствует объекту, на который
указывает указатель "f".
3. Выражение *f имеет все "права" переменной, например
оператор *f=0 означает занесение нуля в тот участок памяти,
адрес которого хранится в переменной – указателе "f".
4. Разыменовывание указателя, соответствующего NULL,
недопустимо.

9.

Две эквивалентные группы операторов
int b;
float f, a;
f=a+b;
и
int b;
float f, a, *c;
с=&f; // указателю с присваивается адрес переменной f
*c=a+b; // значение суммы заносится в участок
// памяти по адресу, равному значению указателя с

10.

Унарные операции сложения ++ и вычитания – –
Позволяют увеличить или уменьшить значение указателя на
величину, равную длине участка памяти, занимаемого
соответствующим типом данных. Тем самым
обеспечивается переход к началу участка памяти для
соседней переменной.
В частности, переменные типа char занимают в памяти участок длиной в 1
байт, переменные типа int – два байта, переменные типа long int и float
– 4 байта, переменные double – 8 байт, long double – 10 байт.

11.

Аддитивные операции
В полном объеме эти операции не разрешены. Переменные
типа указатель нельзя суммировать, но к переменной типа
указатель можно добавлять целую величину k. При этом
указатель увеличивается на величину k*r, где r – длина участка
в байтах, занимаемого соответствующей переменной. Так при
добавлении к указателю переменной типа float величины,
равной трем, указатель увеличится на значение 3*4 = 12 байт.
Аналогично изменяется значение указателя при вычитании из
его значения целой величины.
Операция вычитания применима к указателям одного типа. Из
значения одного указателя можно вычитать значение другого
указателя. Результатом операции является целая величина со
знаком. Значение результата формируется в "масштабе"
соответствующего типа данных. Например, при вычитании
указателей двух соседних величин типа int результат будет
равнее единице, а не двум, хотя переменные этого типа
занимают два байта.

12.

Операции сравнения (<, >, <=, >=, ==, !=)
Применимы только при сопоставлении указателей одного типа
или при сравнении указателя с константой NULL.

13.

Операция получения адреса
Позволяет получить адрес указателя. Указатель является
переменной, поэтому и к нему применима операция
получения адреса. Например, следующий фрагмент
программы позволит отобразить значение адреса указателя
float *a;
printf("\n адрес указателя %p", &a);
Отображение указателей и адресов производится с
использование спецификации р – представление
шестнадцатеричных чисел.
Отображение результатов вычитания указателей осуществляется
с использованием спецификации d для целых чисел.

14. 3. Применение указателей

15.

Применение указателей при работе с массивами
В языке Си при традиционном объявлении массива его имя
становится указателем на начало области памяти,
выделенной под массив, т.е. имя массива без индексов
является указателем на первый элемент, т.е. элемент с
нулевым индексом этого массива.
В частности:
float r[10], *pn1;
pn1=r;
pn1=&r[0];
В этом фрагменте программы два последних оператора
эквиваленты.

16.

Элементы массива в памяти располагаются последовательно друг
за другом, поэтому, изменяя указатель на величину, равную
длине элемента массива, можно переходить к соседним
элементам.
Имя массива интерпретируется как указатель – константа, следовательно, к
нему не применимы операции изменения значений, оно не может стоять слева
от знака присваивания.
Фрагмент программы для подсчета среднего значения элементов
массива с применением указателей
float r[10],s, *pn1;
for (pn1=&r[0], s=0; pn1<=&r[9]; s+=*pn1, pn1++);
s/=10;

17.

В приведенном примере тело цикла отсутствует (за
оператором for стоит символ ";"), все действия по подсчету
суммы записаны в заголовке цикла.
Выражения:
pn1=&r[0]
обеспечивает установку указателя на первый (т.е. нулевой)
элемент массива;
s+=*pn1
суммирование элементов массива;
pn1++
изменение указателя для перехода к следующему элементу
массива (фактическое приращение указателя происходит не
на единицу, а на 4, так как каждый элемент в памяти
занимает 4 байта).
Операция индексирования r[i] эквивалентна *(r+i), где r – имя массива, i –
выражение целого типа. Для многомерных массивов правило остается
такое же. Например, z22[n] [m] [k] эквивалентно *( z22[n] [m] +k) и далее
*(*(*(z22+n)+m)+k).

18.

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

19.

Применение указателей на функции
Необходимость применения указателей на функции связана с
передачей параметра – имени функции в другую функцию или
с возвратом значения – имени функции.
Подобно имени массива наиболее часто в качестве указателя на
функцию применяется идентификатор функции. Этот
идентификатор задается при определении или описании
прототипа функции, т.е. имя и указатель на функцию являются
синонимами, но в обычном контексте термин указатель не
применяется, принято говорить об имени функции. В таком
виде указатель на функцию является константой, поэтому
изменять его нельзя.

20.

Для применения указателя на функцию вводят специальную
переменную. Объявление переменной – указателя на
функцию производится отдельно от определения и от
прототипа функции с помощью конструкции вида:
тип (*имя указателя)(спецификация параметров);
где тип – определяет тип возвращаемого функцией значения;
имя указателя – выбранный программистом идентификатор;
спецификация параметров – определяет состав и типы
параметров функции.
Пример объявления переменной – указателя на функцию
float (*uk1)(float, int);
Здесь указатель имеет имя uk1 (обязательно записывается в
круглых скобках), функция имеет два параметра (типа float и
int), возвращаемое функцией значение имеет тип float.

21.

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

22.

Иллюстрация способов обращения к функции

void f1(float x)
{
printf("\nf1=%6.2f",10*sin(x));
}
void f2(float x)
{
printf ("\nf2=7.4",2*cos(x));
}
void main()
{
void (*u1)(float);// *u1 указатель на функцию

23.


f1(y); // обычный вызов функции
u1=f1; // настройка указателя на функцию f1
u1(y); // вызов функции f1 по указателю
//вызов функции f1 с разыменованием указателя
(*u1)(y);
u1=f2; // настройка указателя на функцию f2
u1(y); // вызов функции f2 по указателю
//вызов функции f2 с разыменованием указателя
(*u1)(y);
}

24.

В языке Python нет указателей в том виде, как они представлены в языках
программирования C или C++.
В Python переменные хранят ссылки на объекты:
* Переменная не хранит непосредственно данные, а хранит ссылку на место в
памяти, где находится объект.
* Когда вы изменяете значение переменной, вы не изменяете объект, а просто
указываете на другой объект.
Пример:

25.

Концепция "указателей" в Python:
* В Python, некоторые функции могут принимать аргументы "по ссылке", что означает,
что они получают ссылку на объект, а не копию.
* Изменение объекта внутри функции влияет на исходный объект.
* Это не то же самое, что "указатели" в языках C/C++.
Почему Python не использует указатели:
* Python ориентирован на простоту и безопасность.
* Указатели могут привести к непредсказуемому поведению программы, если с ними
обращаться неправильно.
* Python использует ссылки, которые более безопасны и позволяют разработчикам
легко управлять данными.
English     Русский Rules