Как удалить двумерный динамический массив c
Перейти к содержимому

Как удалить двумерный динамический массив c

  • автор:

Как удалить двумерный динамический массив c

Друзья-товарищи, изучаю массивы. Ну и как бы все клево, но. Не дает спать мне один момент — освобождение памяти. Перепробовал уже хз все, что мог. Суть вопроса вот в чем, есть код:

#include using namespace std; int rows = 0, cols = 0; int **_array = new int*[rows]; void crt_array() < for (int i = 0; i < rows; i++) < _array[i] = new int[cols]; for (int j = 0; j < cols; j++) _array[i][j] = rand() % 400 + 100; >> void del_array() < for (int i = 0; i < rows; i++) delete[] _array[i]; delete[] _array; > void prt_array() < for (int i = 0; i < rows; i++) < for (int j = 0; j < cols; j++) cout > void main() < setlocale(LC_ALL, "Russian"); cout > rows; cout > cols; crt_array(); prt_array(); del_array(); system("pause"); >

Ничего сверхъестественного, но при попытке освободить память, начинает дергаться вена на лбу. CRT обнаруживает, что приложение пытается что-то записать в память после окончания буфера кучи.

Есть второй код, с одномерным массивом — проблема та же:

#include #include using namespace std; int main() < setlocale(LC_ALL, "Russian"); srand(time(NULL)); int size = 0, min_ipos = 0; int *arr = new int[size]; cout > size; cout cout cout delete[] arr; return 0; > for (min_ipos; min_ipos < size; min_ipos++) < if (min_ipos != (size-1)) arr[min_ipos] = arr[min_ipos + 1]; else break; >arr[size - 1] = 0; cout << "\t"; for (int i = 0; i < size; i++) < cout cout delete[] arr; return 0; system("pause"); >

Красным выделил источник уничтожения нервных клеток. Самое интересное, что если разбить этот второй код по функциям — все работает отлично, вот пример:

#include #include using namespace std; void assig_arr(int *arr, int size) < for (int i = 0; i < size; i++) arr[i] = rand() % 400 + 100; >void findm_arr(int *arr, int size, int &min_ipos) < int min_i = arr[0]; for (int i = 1; i < size; i++) if (arr[i] < min_i) < min_i = arr[i]; min_ipos = i; >> int replg_arr(int *arr, int size, int &min_ipos) < if (min_ipos == size - 1) // Если минимальное значение в массиве крайнее, то просто подставляем ноль и выходим из функции return arr[size - 1] = 0; for (min_ipos; min_ipos < size; min_ipos++) // Начинаем цикл элементом с минимальным значением < if (min_ipos != size - 1) // Если текущий элемент не равен крайнему элементу массива, копируем данные с соседнего элемента arr[min_ipos] = arr[min_ipos + 1]; else break; // Во всех остальных случаях выходим из цикла (чтобы не скопировать данные, которые находятся за пределами массива) >return arr[size - 1] = 0; // После результата работы цикла, задаем крайнему элементу массива значение - ноль > void print_arr(int *arr, int size) < cout void main() < setlocale(LC_ALL, "Russian"); srand(time(NULL)); int size = 0, min_ipos = 0; cout > size; int *arr = new int[size]; // Генерация динамического массива, чтобы задать длинну в ходе выполнения программы assig_arr(arr, size); // Задаем случайные значения элементам массива (от 100 - 500) print_arr(arr, size); // Выводим на экран изначальный массив findm_arr(arr, size, min_ipos); // Поиск минимального значения replg_arr(arr, size, min_ipos); // Удаление мин. значения, сдвиг и присваиваем ноль в крайний элемент print_arr(arr, size); // Выводим на экран измененный массив delete[] arr; // Освобождение памяти system("pause"); >

Заранее спасибо!
Последний раз редактировалось c3nwen; 02.06.2018 в 01:04 .

Как удалить двумерный динамический массив c

Кроме отдельных динамических объектов в языке C++ мы можем использовать динамические массивы. Для выделения памяти под динамический массив также используется оператор new , после которого в квадратных скобках указывается, сколько массив будет содержать объектов:

int *numbers ; // динамический массив из 4 чисел // или так // int *numbers = new int[4];

Причем в этом случае оператор new также возвращает указатель на объект типа int — первый элемент в созданном массиве.

В данном случае определяется массив из четырех элементов типа int, но каждый из них имеет неопределенное значение. Однако мы также можем инициализировать массив значениями:

int *numbers1 >; // массив состоит из чисел 0, 0, 0, 0 int *numbers2 >; // массив состоит из чисел 1, 2, 3, 4 int *numbers3 >; // массив состоит из чисел 1, 2, 0, 0 // аналогичные определения массивов // int *numbers1 = new int[4]<>; // массив состоит из чисел 0, 0, 0, 0 // int *numbers1 = new int[4](); // массив состоит из чисел 0, 0, 0, 0 // int *numbers2 = new int[4]< 1, 2, 3, 4 >; // массив состоит из чисел 1, 2, 3, 4 // int *numbers3 = new int[4]< 1, 2 >; // массив состоит из чисел 1, 2, 0, 0

При инициализации массива конкретными значениями следует учитывать, что если значений в фигурных скобках больше чем длина массива, то оператор new потерпит неудачу и не сможет создать массив. Если переданных значений, наоборот, меньше, то элементы, для которых не предоставлены значения, инициализируются значением по умолчанию.

Стоит отметить, что в стандарт С++20 добавлена возможность выведения размера массива, поэтому, если применяется стандарт С++20, то можно не указывать длину массива:

int *numbers >; // массив состоит из чисел 1, 2, 3, 4

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

int *numbers >; // получение элементов через синтаксис массивов std::cout 

Причем для доступа к элементам динамического массива можно использовать как синтаксис массивов ( numbers[0] ), так и операцию разыменования ( *numbers )

Соответственно для перебора такого массива можно использовать различные способы:

unsigned n< 5 >; // размер массива int* p < new int[n] < 1, 2, 3, 4, 5 >>; // используем индексы for (unsigned i<>; i < n; i++) < std::cout std::cout ; i < n; i++) < std::cout std::cout ; q != p + n; q++) < std::cout std::cout 

Обратите внимание, что для задания размера динамического массива мы можем применять обычную переменную, а не константу, как в случае со стандартными массивами.

Для удаления динамического массива и освобождения его памяти применяется специальная форма оператора delete :

delete [] указатель_на_динамический_массив;

#include int main() < unsigned n< 5 >; // размер массива int* p < new int[n] < 1, 2, 3, 4, 5 >>; // используем индексы for (unsigned i<>; i < n; i++) < std::cout std::cout

Чтобы после освобождения памяти указатель не хранил старый адрес, также рекомендуется обнулить его:

delete [] p; p = nullptr; // обнуляем указатель

Многомерные массивы

Также мы можем создавать многомерные динамические массивы. Рассмотрим на примере двухмерных массивов. Что такое по сути двухмерный массив? Это набор массив массивов. Соответственно, чтобы создать динамический двухмерный массив, нам надо создать общий динамический массив указателей, а затем его элементы - вложенные динамические массивы. В общем случае это выглядит так:

#include int main() < unsigned rows = 3; // количество строк unsigned columns = 2; // количество столбцов int** numbers>; // выделяем память под двухмерный массив // выделяем память для вложенных массивов for (unsigned i<>; i < rows; i++) < numbers[i] = new int[columns]<>; > // удаление массивов for (unsigned i<>; i < rows; i++) < delete[] numbers[i]; >delete[] numbers; >

Вначале выделяем память для массива указателей (условно таблицы):

int** numbers>;

Затем в цикле выделяем память для каждого отдельного массива (условно строки таблицы):

numbers[i] = new int[columns]<>;

Освобождение памяти идет в обратном порядке - сначала освобождаем память для каждого отдельного вложенного массива, а затем для всего массива указателей.

Пример с вводом и выводом данных двухмерного динамического массива:

#include int main() < unsigned rows = 3; // количество строк unsigned columns = 2; // количество столбцов int** numbers>; // выделяем память под двухмерный массив for (unsigned i<>; i < rows; i++) < numbers[i] = new int[columns]<>; > // вводим данные для таблицы rows x columns for (unsigned i<>; i < rows; i++) < std::cout ; j < columns; j++) < std::cout > numbers[i][j]; > > // вывод данных for (unsigned i<>; i < rows; i++) < // выводим данные столбцов i-й строки for (unsigned j<>; j < columns; j++) < std::cout std::cout for (unsigned i<>; i < rows; i++) < delete[] numbers[i]; >delete[] numbers; >

Пример работы программы:

Enter data for 1 row 1 column: 2 2 column: 3 Enter data for 2 row 1 column: 4 2 column: 5 Enter data for 3 row 1 column: 6 2 column: 7 2 3 4 5 6 7

Указатель на массив

От типа int** , который представляет указатель на указатель (pointer-to-pointer) следует отличать ситуацию "указатель на массив" (pointer to array). Например:

#include int main() < unsigned n; // количество строк int (*a)[2] = new int[n][2]; int k<>; // устанавливаем значения for (unsigned i<>; i < n; i++) < // устанавливаем данные для столбцов i-й строки for (unsigned j<>; j < 2; j++) < a[i][j] = ++k; >> // вывод данных for (unsigned i<>; i < n; i++) < // выводим данные столбцов i-й строки for (unsigned j<>; j < 2; j++) < std::cout std::cout // удаляем данные delete[] a; a = nullptr; >

Здесь запись int (*a)[2] представляет указатель на массив из двух элементов типа int. Фактически мы можем работать с этим объектом как с двухмерным массивом (таблицей), только количество столбцов в данном случае фиксировано - 2. И память для такого массива выделяется один раз:

int (*a)[2] = new int[n][2];

То есть в данном случае мы имеем дело с таблице из n строк и 2 столцов. Используя два индекса (для строки и столца), можно обращаться к определенному элементу, установить или получить его значение. Консольный вывод данной программы:

1 2 3 4 5 6

C++. Правильное удаление динамического двумерного массива

Всем привет. Я новичок в программировании и только начинаю многое осваивать(хотя и имею кое-какую подготовку, но считать её хоть сколь-либо серьезной смешно). Знакомлюсь с классами, пытаясь соорудить нечто для работы с матрицами. Код реализации не важен, важно то, что получаю ошибку: http://prntscr.com/e6y5on Ключевой вопрос в том, как её исправить. Matrix.h:

#ifndef MATRIX_H #define MATRIX_H class Matrix < private: int m_rows = 1; int m_cols = 1; int** m_matrix = new int* [m_rows]; public: Matrix(int rows, int cols); void SetSize(int rows, int cols); void Create(); int rows(); int cols(); ~Matrix(); >; #endif 
#include #include #include "matrix.h" using namespace std; Matrix::Matrix(int rows, int cols) < SetSize(rows, cols); Create(); >void Matrix::SetSize(int rows, int cols) < m_rows = rows; m_cols = cols; >void Matrix::Create() < for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout int Matrix::rows() < return m_rows; >int Matrix::cols() < return m_cols; >Matrix::~Matrix()
int main()

При пошаговой проверке в Visual Studio программа сыплется на удалении внешнего указателя delete[] m_matrix; Собственно, прошу помочь =)

Отслеживать
44.8k 3 3 золотых знака 39 39 серебряных знаков 90 90 бронзовых знаков
задан 10 фев 2017 в 13:08
43 1 1 золотой знак 1 1 серебряный знак 3 3 бронзовых знака
Было бы лучше, если бы вы добавили текст ошибки в вопрос не как ссылку
10 фев 2017 в 13:23
Буду иметь ввиду. Новичок на stackoverflow)
10 фев 2017 в 16:20

5 ответов 5

Сортировка: Сброс на вариант по умолчанию

int m_rows = 1; int m_cols = 1; int** m_matrix = new int* [m_rows]; 

Итак, у вас сразу выделяется память и создается матрица 1x1. Поскольку в конструкторе

Matrix::Matrix(int rows, int cols) 

у вас нет инициализации членов, они инициализированы по умолчанию этой матрицей.
Но что вы делаете дальше? Вы переписываете m_rows и m_cols , и в уже выделенный массив для ОДНОГО указателя записываете их m_rows , т.е. в данном конкретном случае - два.

Вот вам и источник ваших неприятностей. Ваша попытка исправить ситуацию - это просто попытка не заметить ошибку. Ни к чему хорошему привести это не может. В следующий раз вы запишете туда их с десяток, и таки засорите память основательнее, только и всего.

Вот как по-хорошему должна выглядеть ваша матрица:

class Matrix < private: int m_rows; int m_cols; int** m_matrix; public: Matrix(int rows, int cols); void SetSize(int rows, int cols); void Create(); int rows(); int cols(); ~Matrix(); >; Matrix::Matrix(int rows, int cols) :m_rows(rows),m_cols(cols) < m_matrix = new int*[m_rows]; for (int i = 0; i < m_rows; i++) m_matrix[i] = new int[m_cols]; cout Matrix::~Matrix()

Правильное удаление двумерного динамического массива ( нужен ли delete[] array )

Author24 — интернет-сервис помощи студентам

ЦитатаСообщение от -=ЮрА=- Посмотреть сообщение

в результате arr[i] - уничтожается(удалиться указатель вместе с элементами строки), тогда если делать так delete [] arr мы будем пытаться удалить уже пустой объёкт!(Не нужно делать масло маслянным)

Я так и не смог понять:
- правда ли, что удаляются указатели на строки в цикле и действительно можно не использовать delete [] arr? Мне непонятно каким образом указатели-то удаляются в цикле.
Хочу увидеть ответы и других участников форума.

Добавлено через 4 часа 23 минуты
поднимаю тему

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *