Лекция 4. Указатели¶
Знакомство с указателями¶
Понятие указателя¶
Понятие указателя¶
Косвенный доступ
int count=154;
int*p=&count;
(*p)++;
printf("Address: %x\n",p);
p - переменная-указатель, используемая для хранения адреса переменной count.
Указатели на указатели¶
Косвенный доступ второго порядка
int count=154;
int*p=&count;
int**pp=&p;
- p - указатель на тип int.
- pp - указатель на указатель на тип int.
- *pp- доступ к значению р
- **pp – доступ к значению count
Применение указателей¶
- передача параметров в функцию;
- манипуляции адресами;
- повышение эффективности кода;
- организация динамических массивов;
- формирование связей между объектами;
Особенности работы с указателями¶
Особенности:
- указатель всегда объявляется на определенный тип;
- размер указателя определяется разрядностью ОС;
- при работе с разнотипными указателями необходимо использовать явное преобразование типа;
Можно объявить указатель на:
- обычную скалярную переменную;
- массив;
- функцию;
- указатель.
Объявление и инициализация указателей¶
Объявление и присваивание
int val1=0;
char ch='#';
double pi=3.14159265358;
int*p1;
char* p2;
double*p3;
p1=&val1;
p2=&ch;
p3=π
Объявление и инициализация
int val1=0;
char ch='#';
double pi=3.14159265358;
int *p1 =&val1;
char* p2 =&ch;
double *p3 =π
Второй вариант более безопасен, поскольку указатели не остаются без значений.
Пример работы с указателями (1)¶
Что будет выведено на экран?
int a=10,b=20;
int * pa=&a;
int * pb=&b;
int *temp;
printf("A=%d, B=%d\n",*pa,*pb);
printf("A=%d, B=%d\n",a,b);
temp=pa;
pa=pb;
pb=temp;
printf("A=%d, B=%d\n",*pa,*pb);
printf("A=%d, B=%d\n",a,b);
Пример работы с указателями (2)¶
Что будет выведено на экран?
int a=10,b=20,temp;
int * pa=&a;
int * pb=&b;
printf("A=%d, B=%d\n",*pa,*pb);
printf("A=%d, B=%d\n",a,b);
temp=*pa;
*pa=*pb;
*pb=temp;
printf("A=%d, B=%d\n",*pa,*pb);
printf("A=%d, B=%d\n",a,b);
Адресная арифметика¶
Операции над значениями указателей¶
Инкремент значения указателя
int a=0;
int * pa=&a;
pa++;

Адрес увеличивается на размер типа данных в байтах
A2=A1+sizeof(int)
В результате указатель содержит адрес ячейки, вплотную прилегающей к исходной (обращение к ней опасно!)
Наиболее естественно использовать указатели с массивами:

Инкремент значения указателя
int arr[]={1,2,3,4,5,6,7,8,9,0};
int *p1=&arr[0];
int *p2=&arr[9];
int size=p2-p1;
Связывание указателя с началом массива:
int *p=arr;
int *p1=&arr[0];
int *p2=p1+2;
int size=p2-p1;
Указатели и массивы¶
Связывание указателей с массивами¶
Указатели и массивы¶
Суммирование элементов массива
int arr[N]={1,2,3,4,5,
6,7,8,9,0};
int *p=arr,sum=0;
while(p<arr+N)
sum+=*p++;
Обработка строки
char str[N]="a very simple string";
char *p=str;
while(*p)
putchar(*p++);
Массивы указателей¶
Массив указателей на char можно использовать для создания массива строковых констант
int *pa[10];
char *str[5];
char *mes[]={"Divide by 0" ,
"File not found" ,
"Not enough memory"
};
...
printf("%s", mes[errcod]);
...
Организация массива указателей
Что означают следующие выражения?
Взаимозаменяемость¶
Имена массивов и указателей могут быть эквиваленты
Следующие выражения эквивалентны:
int arr[10];
arr[5] = 5 [arr] = *( arr+ 5)
int *p=arr;
p[5] = *(p+5)
int arr[5];
int *parr=arr;
*(parr+2)=0;
parr[2]++;
Имя массива может выступать в операции как имя указателя-константы, а имя указателя может действовать как имя массива с использованием []
Строки и указатели¶
Строка может быть задана как локальный массив или как указатель на ‘’далёкую’’ текстовую константу
char str[]="A simple string";
char *s="A simple string";

Фиксация указателей¶
Для предотвращения изменения данных, связанных с указателем используют указатели на константу:
const char * p="don't change me!";
При попытке изменить данные по адресу в p появится ошибка компиляции.
Для предотвращения изменения значения указателя (адреса) используют константные указатели:
char * const p="don't lost me!";
При попытке изменить адрес в указателе появится ошибка компиляции.
Константный указатель на константу:
const char * const p="don't touch me!";
Указатели на функцию¶
Указатель на функцию хранит адрес точки входа в тело функции.
Указатель объявляется на функцию с определенным возвращаемым значением и набором параметров.
// математические функции с похожими прототипами
double sin(double x);
double cos(double x);
double exp(double x);
// объявление указателя на функцию
double (*pfun)(double);
// использование указателя
pfun=sin; // pfun=&sin;
// теперь можно вызывать функцию с помощью указателя
y=pfun(x); // y=(*pfun)(x);
Указатель можно связать с другой функцией и при обращении к его значению будет вызвана другая функция
Вопросы для самоконтроля¶
- Какие бывают способы адресации?
- В чем состоит прямой доступ к переменной?
- Что такое косвенная адресация?
- Как объявить и использовать указатель на указатель?
- Для чего используются указатели?
- В чем состоят особенности работы с указателями?
- На что объявить указатель?
- Как объявить и инициализировать указатель?
- В чем опасность непроинициализированных указателей?
- Как работает инкремент значения указателя?
- Как связать указатель и массив?
- Что представляет из себя массив указателей?
- В каком смысле говорят о взаимозаменяемости массивов и указателей?
- Чем отличается строка, заданная с помощью указателя от строки, заданной с помощью массива?
- Что такое указатель на константу? Как его объявить?
- Что такое константный указатель? Как его записать?
- Что такое константный указатель на константу? Как его использовать?
- Как объявить указатель на массив?
- Чем отличается указатель на массив от массива указателей?
- Где используются указатели на массивы?
- Как объявить и использовать указатель на функцию?