Указатели в С++

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

Указатель — это переменная, которая хранит адрес памяти другой переменной. В C++ указатели используются для:

  • Прямого доступа к памяти

  • Динамического выделения памяти

  • Эффективной передачи больших данных в функции

  • Реализации сложных структур данных


Синтаксис и базовые операции
Объявление указателя:
тип* имя_указателя; // * может быть рядом с типом или именем
Примеры инициализации:
int num = 42; int* ptr = # // ptr хранит адрес num double d = 3.14; double* dPtr = &d; char c = 'A'; char* cPtr = &c;
Операции с указателями:
int x = 10; int* p = &x; cout << p; // Выведет адрес памяти (например, 0x7ffd4d96e8ac) cout << *p; // Выведет 10 (разыменование) *p = 20; // Изменяем значение x через указатель cout << x; // Теперь x = 20
Указатель на указатель
int val = 5; int* ptr = &val; int** pptr = &ptr; // Указатель на указатель cout << **pptr; // Выведет 5
Арифметика указателей

Указатели поддерживают операции +, -, ++, -- с учетом размера типа:

int arr[5] = {10, 20, 30, 40, 50}; int* ptr = arr; // Эквивалентно &arr[0] cout << *ptr; // 10 ptr++; // Перемещаемся на следующий int (4 байта) cout << *ptr; // 20 cout << *(ptr+2); // 40
Указатели и массивы

Массивы неявно преобразуются в указатели:

int nums[3] = {1, 2, 3}; int* p = nums; // p указывает на nums[0] // Эквивалентные способы доступа: cout << nums[1]; // 2 cout << *(p+1); // 2 cout << p[1]; // 2 (синтаксический сахар)
Указатели на функции
// Объявление функции int add(int a, int b) { return a + b; } // Указатель на функцию int (*funcPtr)(int, int) = &add; // Вызов через указатель int result = funcPtr(3, 4); // result = 7
Нулевые указатели
int* ptr1 = nullptr; // Современный C++ (предпочтительно) int* ptr2 = NULL; // Устаревший стиль int* ptr3 = 0; // Альтернатива if (ptr1 == nullptr) { cout << "Указатель не инициализирован"; }
Динамическая память
int* dynArr = new int[10]; // Выделение памяти dynArr[0] = 42; delete[] dynArr; // Освобождение памяти int* single = new int(7); // Одиночное выделение delete single;

Для чего нужны указатели?

Динамическое выделение памяти

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

int size; cin >> size; // Размер массива вводит пользователь int* dynamicArray = new int[size]; // Без указателя так не сделать for (int i = 0; i < size; ++i) { dynamicArray[i] = i * 10; } delete[] dynamicArray; // Освобождаем память

Почему без указателей нельзя?
Массивы с размером из переменной (int arr[size]) — запрещены в стандартном C++. Только через new и указатели.

Работа с функциями
а) Изменение переменных внутри функций

Без указателей функция не может изменить переданную переменную:

void increment(int* num) { (*num)++; // Разыменовываем указатель и меняем значение } int main() { int x = 5; increment(&x); // Передаём адрес x cout << x; // 6 }
б) Возврат нескольких значений

Через указатели можно "вернуть" несколько значений:

void calculate(int a, int b, int* sum, int* product) { *sum = a + b; *product = a * b; } int main() { int s, p; calculate(3, 4, &s, &p); cout << "Sum: " << s << ", Product: " << p; }
Работа с массивами и строками

Указатели позволяют эффективно обрабатывать данные:

void printArray(const int* arr, int size) { for (int i = 0; i < size; ++i) { cout << arr[i] << " "; } } int main() { int nums[] = {1, 2, 3}; printArray(nums, 3); // Передаём массив через указатель }

Почему не копировать массив?
Копирование больших массивов — дорогая операция. Указатели экономят память и время.

Создание сложных структур данных

Без указателей невозможны:

  • Связные списки

  • Деревья

  • Графы

Пример узла списка:

struct Node { int data; Node* next; // Указатель на следующий узел }; Node* head = new Node{1, new Node{2, nullptr}};
Взаимодействие с оборудованием и ОС
  • Чтение/запись в конкретные адреса памяти (например, в драйверах)

  • Работа с API операционной системы (например, WinAPI)


Комментарии

Добавить комментарий

Чтобы оставить комменатрий необходимо Авторизоваться