C++ 1, осень 2014: Указатели и ссылки

18
Лекция 3. Массивы, указатели и ссылки Лекция 3. Массивы, указатели и ссылки Александр Смаль CS центр 24 сентября 2014 Санкт-Петербург http://compscicenter.ru 1/18

description

Передача параметра с помощью указателя. Взятие адреса переменной и, наоборот, значения по адресу. Неинициализированные указатели. Нулевой указатель. Массивы и указатели. Арифметика указателей. Потенциальные проблемы при использовании указателей. Ссылки. Сходство с ссылок с указателями и их отличия. Как хранятся ссылки. lvalue и rvalue

Transcript of C++ 1, осень 2014: Указатели и ссылки

Page 1: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Лекция 3. Массивы, указатели иссылки

Александр Смаль

CS центр24 сентября 2014Санкт-Петербург

http://compscicenter.ru 1/18

Page 2: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Указатели∙ Указатель — это переменная, хранящая адрес некоторой

ячейки памяти.∙ Указатели являются типизированными.

int i = 3; // переменная типа intint * p = 0; // указатель на переменную типа int

∙ Нулевому указателю (которому присвоено значение 0)не соответствует никакая ячейка памяти.

∙ Оператор взятия адреса переменной &.∙ Оператор разыменования *.

p = &i; // указатель p указывает на переменную i*p = 10; // изменяется ячейка по адресу p, т.е. i

http://compscicenter.ru 2/18

Page 3: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Передача параметров по указателюРассмотрим функцию, меняющую параметры местами:

void swap (int a, int b) {int t = a;a = b;b = t;

}

int main() {int k = 10, m = 20;swap (k, m);cout << k << ’ ’ << m << endl; // 10 20return 0;

}

swap изменяет локальные копии переменных k и m.

http://compscicenter.ru 3/18

Page 4: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Передача параметров по указателюВместо значений типа int будем передавать указатели.

void swap (int * a, int * b) {int t = *a;*a = *b;*b = t;

}

int main() {int k = 10, m = 20;swap (&k, &m);cout << k << ’ ’ << m << endl; // 20 10return 0;

}

swap изменяет переменные k и m по указателям на них.

http://compscicenter.ru 4/18

Page 5: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Массивы∙ Массив — это набор однотипных элементов,

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

∙ C++ позволяет определять массивы на стеке.

// массив 1 2 3 4 5 0 0 0 0 0int m[10] = {1, 2, 3, 4, 5};

∙ Индексация массива начинается с 0, последний элементмассива длины n имеет индекс n - 1.

for (int i = 0; i < 10; ++i)cout << m[i] << ’ ’;

cout << endl;

http://compscicenter.ru 5/18

Page 6: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Связь массивов и указателей∙ Указатели позволяют передвигаться по массивам.∙ Для этого используется арифметика указателей:

int m[10] = {1, 2, 3, 4, 5};int * p = &m[0]; // адрес начала массиваint * q = &m[9]; // адрес последнего элемента

∙ (p + k) — сдвиг на k ячеек типа int вправо.∙ (p - k) — сдвиг на k ячеек типа int влево.∙ (q - p) — количество ячеек между указателями.∙ p[k] эквивалентно *(p + k).

1 2 3 4 5 0 0 0 0 0

p q(p + 2) (q - 4)

http://compscicenter.ru 6/18

Page 7: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

ПримерыЗаполнение массива:

int m[10] = {}; // изначально заполнен нулями// &m[0] &m[9]for (int * p = m ; p <= m + 9; ++p )

*p = (p - m) + 1;// Массив заполнен числами от 1 до 10

Передача массива в функцию:

int max_element (int * m, int size) {int max = *m;for (int i = 1; i < size; ++i)

if (m[i] > max)max = m[i];

return max;}

http://compscicenter.ru 7/18

Page 8: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Два способа передачи массиваbool contains(int * m, int size , int value) {

for (int i = 0; i != size; ++i)if (m[i] == value)

return true;return false;

}bool contains(int * p, int * q, int value) {

for (; p != q; ++p)if (*p == value)

return true;return false;

}

1 2 3 4 5 0 0 0 0 0

p qhttp://compscicenter.ru 8/18

Page 9: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Возрат указателя из функции

Функция для поиска максимума в массиве:

int max_element (int * p, int * q) {int max = *p;for (; p != q; ++p)

if (*p > max)max = *p;

return max;}

int m[10] = {...};int max = max_element(m, m + 10);cout << "Maximum = " << max << endl;

http://compscicenter.ru 9/18

Page 10: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Возрат указателя из функции

Функция для поиска максимума в массиве:

int * max_element (int * p, int * q) {int * pmax = p;for (; p != q; ++p)

if (*p > *pmax)pmax = p;

return pmax;}

int m[10] = {...};int * pmax = max_element(m, m + 10);cout << "Maximum = " << *pmax << endl;

http://compscicenter.ru 10/18

Page 11: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Возрат значения через указательФункция для поиска максимума в массиве:

bool max_element (int * p, int * q, int * res) {if (p == q)

return false;*res = *p;for (; p != q; ++p)

if (*p > *res)*res = *p;

return true;}

int m[10] = {...};int max = 0;if (max_element(m, m + 10, &max))

cout << "Maximum = " << max << endl;

http://compscicenter.ru 11/18

Page 12: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Возрат значения через указатель на указательФункция для поиска максимума в массиве:

bool max_element (int * p, int * q, int ** res) {if (p == q)

return false;*res = p;for (; p != q; ++p)

if (*p > **res)*res = p;

return true;}

int m[10] = {...};int * pmax = 0;if (max_element(m, m + 10, &pmax))

cout << "Maximum = " << *pmax << endl;

http://compscicenter.ru 12/18

Page 13: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Недостатки указателей

∙ Использование указателей синтаксически загрязняет код иусложняет его понимание. (Приходится использоватьоператоры * и &.)

∙ Указатели могут быть неинициализированными(некорректный код).

∙ Указатель может быть нулевым (корректный код), азначит указатель нужно проверять на равенство нулю.

∙ Арифметика указателей может сделать из корректногоуказателя некорректный (легко промахнуться).

http://compscicenter.ru 13/18

Page 14: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Ссылки∙ Для того, чтобы исправить некоторые недостатки

указателей, в C++ введены ссылки.∙ Ссылки являются “красивой обёрткой” над указателями:

void swap (int & a, int & b) {int t = b;b = a;a = t;

}

int main() {int k = 10, m = 20;swap (k, m);cout << k << ’ ’ << m << endl; // 20 10return 0;

}

http://compscicenter.ru 14/18

Page 15: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Различия ссылок и указателей∙ Ссылка не может быть неинициализированной.

int * p; // OKint & l; // ошибка

∙ У ссылки нет нулевого значения.

int * p = 0; // OKint & l = 0; // ошибка

∙ Ссылку нельзя переинициализировать.

int a = 10, b = 20;int * p = &a; // p указывает на ap = &b; // p указывает на bint & l = a; // l ссылается на al = b; // a присваивается значение b

http://compscicenter.ru 15/18

Page 16: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Различия ссылок и указателей

∙ Нельзя получить адрес ссылки или ссылку на ссылку.

int a = 10;int * p = &a; // p указывает на aint ** pp = &p;// pp указывает на переменную pint & l = a; // l ссылается на aint * pl = &l; // pl указывает на переменную aint && ll = l; // ошибка

∙ Нельзя создавать массивы ссылок.

int * mp[10] = {}; // массив указателей на intint & ml[10] = {}; // ошибка

∙ Для ссылок нет арифметики.

http://compscicenter.ru 16/18

Page 17: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

lvalue и rvalue∙ Выражения в C++ можно разделить на два типа:

1. lvalue — выражения, значения которых являются ссылкойна переменную/элемента массива, а значит могут бытьуказаны слева от оператора =.

2. rvalue — выражения, значения которых являютсявременными и не соответствуют никакойпеременной/элементу массива.

∙ Указатели и ссылки могут указывать только на lvalue.

int a = 10, b = 20;int m[10] = {1,2,3,4,5,5,4,3,2,1};int & l1 = a; // OKint & l2 = a + b; // ошибкаint & l3 = *(m + a / 2); // OKint & l4 = *(m + a / 2) + 1; // ошибкаint & l5 = (a + b > 10) ? a : b; // OK

http://compscicenter.ru 17/18

Page 18: C++ 1, осень 2014: Указатели и ссылки

Лекция 3. Массивы, указатели и ссылки

Время жизни переменной

Следует следить за временем жизни переменных.

int * foo() {int a = 10;return &a;

}

int & bar() {int b = 20;return b;

}

int * p = foo();int & l = bar();

http://compscicenter.ru 18/18