Указатель на числа подряд
Вернёмся на улицу памяти. Иногда несколько домов стоят вплотную друг к другу, и в каждом лежит по числу. Чтобы рассказать кому-то про весь ряд, не нужно писать адрес каждого дома. Достаточно двух вещей:
- бумажки с адресом первого дома;
- количества домов в ряду.
Дальше человек идёт от первого дома вдоль улицы и считает: нулевой, первый, второй… Так же в C++ функция получает несколько чисел, которые лежат в памяти подряд.
Как получить числа подряд
Запись int data[] = {4, 7, 1}; кладёт три числа int в память одно за другим. Такой ряд называется массивом; подробно массивы разобраны в одной из следующих тем. Когда data передают функции с параметром int*, функция получает указатель на первое число ряда:
#include <iostream>
int sum(int* data, int n) {
int total = 0;
for (int i = 0; i < n; ++i) {
total = total + data[i];
}
return total;
}
int main() {
int data[] = {4, 7, 1};
std::cout << sum(data, 3) << '\n'; // 12
}Давайте разберём пример по строкам:
int data[] = {4, 7, 1};ставит в ряд три дома с числами4,7и1.- Вызов
sum(data, 3)передаёт бумажку с адресом первого дома и количество домов3. - Внутри
sumцикл проходитiот0до2и складываетdata[0],data[1]иdata[2]. - Программа печатает
12, то есть4 + 7 + 1.
Шаг вдоль ряда
Если data указывает на первое число, то data + i указывает на число с номером i. Нумерация начинается с нуля, поэтому номера идут от 0 до n - 1. Есть три записи, которые нужно уметь читать:
data + i— адрес числа с номеромi;data[i]— само число с номеромi, короткая форма*(data + i);&data[i]— тоже адрес числа с номеромi, то же самое, чтоdata + i.
int data[] = {4, 7, 1};
int* p = data + 2;
std::cout << *p << ' ' << data[2] << '\n'; // 1 1
std::cout << (p == &data[2]) << '\n'; // 1Разберём по строкам:
int* p = data + 2;отсчитывает от первого дома два шага и записывает на бумажкуpадрес числа с номером2.*pиdata[2]обозначают одно и то же число, поэтому печатается1 1.p == &data[2]сравнивает два адреса. Они равны, иstd::coutпечатает1, то есть «истина».
Здесь аналогия с улицей заканчивается: в конце ряда нет забора. Улица продолжается чужими домами, и data + n указывает уже за последнее число ряда. Читать data[n] — неопределённое поведение.
Частая ошибка
В цикле написали <= вместо <:
int sum(int* data, int n) {
int total = 0;
for (int i = 0; i <= n; ++i) {
total = total + data[i]; // ✗
}
return total;
}Компилятор не выдаёт ни ошибки, ни предупреждения. Но на последнем шаге цикл читает data[n], то есть число за концом ряда, а это неопределённое поведение. Последний допустимый номер — n - 1, поэтому условие цикла — i < n.
Главное
- Числа подряд передают функции двумя параметрами: указателем на первое число и их количеством.
int data[] = {…}кладёт числа подряд, аdataв параметреint*становится указателем на первое из них.data[i]— это*(data + i), а&data[i]— то же, чтоdata + i.- Номера идут от
0доn - 1; чтениеdata[n]— неопределённое поведение.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.