Как объявить двумерный динамический массив в C++ с помощью оператора new?
Самый распространённый способ: массив указателей на массивы
Это классический подход, который часто используется в C++ и полностью совместим с C. Идея в том, чтобы выделить массив указателей (строки), а затем для каждой строки выделить отдельный массив (столбцы).
#include <iostream>
int main() {
int rows = 3;
int cols = 4;
// 1. Выделяем массив указателей (строки)
int** arr = new int*[rows];
// 2. Для каждой строки выделяем массив int (столбцы)
for (int i = 0; i < rows; ++i) {
arr[i] = new int[cols];
}
// 3. Заполняем массив значениями
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
arr[i][j] = i * cols + j;
}
}
// 4. Выводим массив
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
// 5. ОСВОБОЖДАЕМ ПАМЯТЬ (очень важно!)
for (int i = 0; i < rows; ++i) {
delete[] arr[i]; // удаляем каждую строку
}
delete[] arr; // удаляем массив указателей
return 0;
}
Объяснение:
- int** arr — это указатель на указатель. Первый уровень (arr[i]) — это строка, второй (arr[i][j]) — элемент.
- Память выделяется в два этапа: сначала для строк, потом для столбцов.
- Обращение к элементу:
arr[i][j]— работает как с обычным статическим массивом. - Освобождение в обратном порядке: сначала удаляем каждую строку, потом массив указателей.
Недостатки этого подхода:
- Память выделяется не единым блоком, что может снизить производительность из-за кэш-промахов.
- Требуется больше вызовов new/delete (rows + 1), что увеличивает риск утечек.
Альтернатива: единый блок памяти (рекомендуется для производительности)
Выделяем один большой массив размером rows * cols и эмулируем двумерность через арифметику указателей:
int* arr = new int[rows * cols];
// Доступ к элементу [i][j]:
arr[i * cols + j] = 42;
// Освобождение:
delete[] arr;
Этот способ быстрее, но менее нагляден. Чтобы сохранить синтаксис arr[i][j], можно использовать шаблоны или классы-обёртки.
Современный C++ (C++11 и новее): используйте std::vector
В реальных проектах почти никогда не используют голый new. Лучше взять std::vector:
#include <vector>
std::vector<std::vector<int>> arr(rows, std::vector<int>(cols));
// Или одномерный вектор для производительности:
std::vector<int> arr(rows * cols);
arr[i * cols + j] = 42;
С std::vector память освобождается автоматически, нет риска утечек, и код читается лучше.
Использование умных указателей (smart pointers) для автоматического управления памятью
Если вы всё же хотите работать с двумерным массивом через указатели, но избежать ручного вызова delete[], используйте std::unique_ptr (C++11):
#include <memory>
int rows = 5, cols = 10;
// Создаём массив unique_ptr для каждой строки
std::unique_ptr<int[]> arr[rows];
for (int i = 0; i < rows; ++i) {
arr[i] = std::make_unique<int[]>(cols);
}
// Или одномерный вариант:
auto arr = std::make_unique<int[]>(rows * cols);
arr[i * cols + j] = 42;
Плюсы этого подхода:
- Память освобождается автоматически при выходе из области видимости.
- Нет риска забыть вызвать
delete[]. - Код остаётся эффективным (без накладных расходов, как у std::vector).
Минус: синтаксис всё равно требует арифметики индексов для одномерного варианта. Но это можно обернуть в простой класс или структуру.
Итоговая рекомендация: Для учебных задач — используйте int** с ручным управлением, но для реального кода — std::vector или std::unique_ptr.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Как правильно обрабатывать ошибки в Python: от try-except-finally до ловли всех исключений