Указатели и память

Арифметика указателей в C и C++

В этом уроке вы переберёте элементы массива с помощью арифметики указателей в C и итераторов в C++.

Введение

Если прибавить к указателю 1, он сдвинется не на один байт, а на следующий элемент массива, потому что компилятор учитывает размер типа. Благодаря этому указателем можно проходить по непрерывной области памяти, как по массиву.

Главное

  • Указатель должен указывать только на существующий объект нужного типа или быть равен null.
  • Каждую выделенную область памяти нужно освободить ровно один раз.
  • Явно обозначайте, какая функция владеет памятью (ownership), а какие данные только читаются (const).

Примеры кода на C и C++

C
Запустить →
main.c
#include <stdio.h>

int main(void) {
    int values[] = {10, 20, 30, 40};
    int sum = 0;
    for (int *p = values; p < values + 4; ++p) sum += *p;
    printf("sum=%d distance=%td\n", sum, (values + 4) - values);
    return 0;
}
Результат выполнения
sum=100 distance=4
C++
Запустить →
main.cpp
#include <iostream>
#include <vector>

int main() {
    std::vector values{10, 20, 30, 40};
    int sum = 0;
    for (auto it = values.begin(); it != values.end(); ++it) sum += *it;
    std::cout << "sum=" << sum << " distance="
              << std::distance(values.begin(), values.end()) << '\n';
}
Результат выполнения
sum=100 distance=4

Сравнение C и C++

Цикл начинается с указателя p на первом элементе и движется, пока p не дойдёт до позиции values + 4. На каждом шаге *p берёт текущее значение и прибавляет его к сумме. Арифметика указателей допустима только внутри одного массива или сразу за его последним элементом. В C++ итераторы позволяют так же перебирать самые разные контейнеры.

C

Владение памятью и её освобождение полностью лежат на программисте.

C++

Контейнеры и RAII автоматически освобождают ресурсы, когда заканчивается время жизни объекта.

Упражнения для практики

Запустите обе версии, а затем измените код, чтобы увидеть разницу в безопасности, которую даёт каждый язык.

  • Проверьте работу с нулевыми указателями и при ошибках выделения памяти.
  • Запустите программу с AddressSanitizer и UndefinedBehaviorSanitizer, чтобы найти ошибки работы с памятью.
  • Явно обозначьте, какой указатель владеет памятью, а какой служит только для чтения.

Попрактикуйтесь на задаче

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

Все задачи