Указатели (pointers)

Содержание

Слайд 2

Типы данных С++

Типы данных С++

Слайд 3

1. Назначение указателей Оперативная память компьютера может рассматриваться как массив байтов,

1. Назначение указателей

Оперативная память компьютера может рассматриваться как массив байтов, индексируемый

от нуля. Номер каждого байта в этом массиве называется его адресом.
Адресом переменной называется адрес ее первого байта места хранения.

Переменные, в которых хранятся адреса других переменных, называются указателями.

Указатель – переменная, диапазон значений которой состоит из адресов
ячеек памяти или специального значения — нулевого адреса.
Последнее используется для указания того, что в данный момент указатель
не ссылается ни на одну из допустимых ячеек.

Слайд 4

Назначение указателей (Тематика) Обеспечивают гибкость программирования: указатель (рtr) знает лишь адрес

Назначение указателей (Тематика)

Обеспечивают гибкость программирования:
указатель (рtr) знает лишь адрес переменной

(а), сама переменная может менять свое значение независимо от наличия указателя на нее.

Справочная служба 109.
Адрес – указатель, номер телефона – значение переменной.
Результат: при изменении номера нет необходимости оповещать об этом всех абонентов.
Расчетный счет.
Счет не меняется, а содержимое – сколько угодно.
Результат: достаточно помнить номер счета или карты.
Файловый указатель.
Один и тот же указатель обращается всякий раз к текущему элементу файла, после чего перемещается на следующий.
Результат: через один указатель можно работать с различными данными, находящимися в файле

Примеры:

Слайд 5

Назначение указателей (Техника) Правильное понимание и использование указателей особенно необходимо для

Назначение указателей (Техника)

Правильное понимание и использование указателей особенно необходимо для составления

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

Однако указатель может вызвать и ряд затруднений:
если указатель содержит неправильное значение, программа может быть неработоспособной (access violation).
можно легко ошибиться при использовании указателей;
ошибки, связанные с неправильными значениями указателей, найти очень трудно.

Слайд 6

Объявление указателей При объявлении переменной для нее резервируется память. При определении

Объявление указателей

При объявлении переменной для нее резервируется память.
При определении – этому

участку памяти присваивается значение.

Общая форма объявления указателя:
тип * имя;

int *р; // р – указатель на int
int *р, q; // q – не указатель
int *р, *q; // p и q – указатели
P = NULL; // пустой (нулевой) указатель
void* p; // бестиповый указатель

Нулевой указатель − это указатель, хранящий специальное значение, используемое для того, чтобы показать, что данная переменная-указатель не ссылается (не указывает) ни на какой объект (в С и С++ - это 0 или макрос NULL - нулевой адрес, зарезервирован ОС).

void используется для того, чтобы показать, что указатель означает просто адрес памяти, независимо от типа величины, находящейся по этому адресу

Слайд 7

Операции над указателями Присваивание указателю значение адреса переменной (& - унарная

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

Присваивание указателю значение адреса переменной (& - унарная операция

(амперсанд):
p=&q;
где p – указатель, q – идентификатор переменной,.
2. Определение значения, на которое ссылается указатель (* - унарная операция косвенной адресации или разыменования):
val=*p; // в результате val=q
3. Увеличение (уменьшение) указателя: (+ сложение, ++ инкрементация,  –вычитание, –– декрементация).
Пример:
Если p1 – указатель, то  р1++  перемещает указатель
на 1 байт, если *p1 имеет тип char;
4 байта, если *p1 имеет тип int ;
4 байта, если *p1 имеет тип float.
4. Разность двух указателей. Например, чтобы найти, на каком расстоянии друг от друга находятся элементы массива.
Слайд 8

Пример 2.1: //Даны адреса переменных &a=63384,&b=64390,&c=64404. //Что будет выведено на печать?

Пример 2.1:

//Даны адреса переменных &a=63384,&b=64390,&c=64404. 
//Что будет выведено на печать?
# include 
int main()
{
float a,*p1;
int b,*p2;
char c,*p3;
a=2.5; b=3; c='A';
p1=&a; p2=&b; p3=&c;
p1++; p2++; p3++;
printf("\n p1=%u, p2=%u, p3=%u",p1,p2,p3);
return 0;
}

Ответ: р1=63388, р2=64394, р3=64405.

Слайд 9

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

Правила присваивания указателей

Указатели одного типа можно сравнивать на равенство и неравенство.
Указатели

разных типов несовместимы по присваиванию.

void *UndefPoint;
UndefPoint = 0xb8000000; // недопустимо
UndefPoint++; // Для типа void * нет такой операции…
(int *)UndefPoint++; // И так тоже ничего не получается…
((int *)UndefPoint)++; // А так хорошо… Сколько скобок!
++(int *)UndefPoint; // И вот так тоже хорошо…

Приведение типов указателей

Слайд 10

Указатели и массивы Указатель на массив – это адрес его первого

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

Указатель на массив – это адрес его первого элемента.
Элементы

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

long array[100];  long sum = 0;  for (long* ptr = &array[0]; ptr < &array[99] + 1; ptr++)  sum += *ptr;
//или
for (long* ptr = array; ptr < &array[99] + 1; ptr++)  sum += *ptr;

Смешивать указатели и массивы можно, делать это не рекомендуется!

Слайд 11

Указатели и строки Строка в Си - это последовательность байт (букв,

Указатели и строки

Строка в Си - это последовательность байт (букв, символов), завершающаяся

в конце специальным признаком - байтом '\0'.
Указатель типа char* - это строка.

Использование указателей, а не массивов с фиксированными размерами, особенно целесообразно, когда предложения или слова должны быть разной длины.

char *point[]={"понедельник","вторник",
"среда","четверг", "пятница","суббота",
"воскресенье"};
int i,n;
n=sizeof(point)/sizeof(point[0]);
for(i=0;i < n;i++) {
printf("\n %s",point[i]); // 1)
printf("\n %p",point[i]); // 2)
}

понедельник  вторник  среда  четверг  пятница  суббота  воскресенье

00B8  00C4  00CC  00D2  00DA  00E2  00EA

1)

2)

Слайд 12

Указатели в параметрах функции Изменить значение фактического параметра возможно с помощью

Указатели в параметрах функции

Изменить значение фактического параметра возможно с помощью механизма

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

1)

2)

void main() {
positive(int *m);
int k=-3;
positive(&k);
printf("\n k=%d",k);
getch();}
void positive(int *m){
if (*m < 0)
*m=-*m;
}

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

Слайд 13

Ссылки Ссылка - тот же указатель, т.е. если функции параметр передается

Ссылки

Ссылка - тот же указатель, т.е. если функции параметр передается как

ссылка, то функция работает не с копией параметра, а с самим параметром.

Программа выведет '3'. Если в объявлении 'f' убрать & перед a, то программа выведет 4. Плюс ссылок - не надо пользоваться разыменовыванием (оператор *) и взятием адреса (оператор &). Минус - обязательно надо на что-нибудь ссылаться, то есть нельзя передать NULL как ссылку

int a; // переменная типа int int &b = a; // ссылка на a

void f(int &a)
{ a = 3; }
void main()
{ int k = 4; f(k); printf("%d\n",k); }