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

Указатели и адреса в C и C++

В этом уроке вы сохраните адрес переменной в указателе, обратитесь к значению через этот указатель и измените исходную переменную.

Введение

Указатель (pointer) - это переменная, которая хранит адрес памяти другой переменной. Оператор & даёт адрес переменной, а оператор * (разыменование) обращается к значению по адресу, на который указывает указатель. Указатели - одно из самых важных понятий C и C++.

Главное

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

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

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

int main(void) {
    int score = 70;
    int *score_ptr = &score;
    *score_ptr += 5;
    printf("score=%d same-address=%s\n", score,
           score_ptr == &score ? "yes" : "no");
    return 0;
}
Результат выполнения
score=75 same-address=yes
C++
Запустить →
main.cpp
#include <iostream>

int main() {
    int score = 70;
    int* score_ptr = &score;
    *score_ptr += 5;
    std::cout << "score=" << score << " same-address="
              << std::boolalpha << (score_ptr == &score) << '\n';
}
Результат выполнения
score=75 same-address=true

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

Указатель score_ptr хранит адрес score, поэтому *score_ptr += 5 на самом деле прибавляет 5 к самой переменной score, и она меняется с 70 на 75. Сравнение score_ptr == &score подтверждает, что адреса совпадают. В C++ обычные указатели (raw pointer) по-прежнему используют, когда нужен только доступ к данным без управления памятью, но если переменная никогда не должна быть пустой, предпочитают ссылки.

C

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

C++

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

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

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

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

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

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

Все задачи