Форум программистов, компьютерный форум CyberForum.ru

Выделение динамической памяти для двумерного массива. - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 179, средняя оценка - 4.82
neske
1419 / 786 / 55
Регистрация: 26.03.2010
Сообщений: 2,694
16.04.2010, 19:26     Выделение динамической памяти для двумерного массива. #1
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
 
int main()
{
    setlocale( LC_ALL,"Russian" );
 
    int N, M;
    std::cout << "Введите кол-во строк в массиве: ";
    std::cin >> N;
    std::cout << "Введите кол-во столбцов в массиве: ";
    std::cin >> M;
    int *MAS=new int [N][M];
 
    std::cout << "Первоначальный массив: " << std::endl;
    for (int i=0; i<N; i++) // заполняем массив с клавиатуры.
    for (int j=0; j<M; j++)
    {
        std::cout << "Массив["<<  i <<"]["<< j <<"]: ";
        std::cin >> MAS[i][j];
    }
    
    delete []MAS;
    system("pause");
    return 0;
}
Ошибка 1 error C2540: неконстантное выражение используется в качестве границы массива c:\visual studio 2008\projects\project1\example\example\kod.cpp
Ошибка 1 error C2540: неконстантное выражение используется в качестве границы массива c:\visual studio 2008\projects\project1\example\example\kod.cpp
Ошибка 3 error C2109: для индекса требуется массив или указатель c:\visual studio 2008\projects\project1\example\example\kod.cpp 20
Need help!
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
toxa92
 Аватар для toxa92
167 / 94 / 2
Регистрация: 16.04.2010
Сообщений: 464
16.04.2010, 19:32     Выделение динамической памяти для двумерного массива. #2
надо выделить сначала массив указателей, а потом к каждому указателю прилепить по массиву чисел
neske
1419 / 786 / 55
Регистрация: 26.03.2010
Сообщений: 2,694
16.04.2010, 19:35  [ТС]     Выделение динамической памяти для двумерного массива. #3
Спасибо, можно листинг?
MikeSoft
Эксперт C++
 Аватар для MikeSoft
3781 / 1765 / 85
Регистрация: 21.11.2009
Сообщений: 2,540
16.04.2010, 19:37     Выделение динамической памяти для двумерного массива. #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
neske,

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int x,y;
//----------------------------------------------------------------------------
std::cout << "Введите кол-во строк в массиве: ";
std::cin >> x;
std::cout << "Введите кол-во столбцов в массиве: ";
std::cin >> y;
//------------------------Выделение памяти------------------------------------
int **mas = new int *[x];
 
for (int i = 0; i < x; i++) {
  mas[i] = new int [y];
}
//----------------------------------------------------------------------------
//                      Выполняйте действия, которые вам необходимы
//--------------------------Освобождение памяти----------------------------
for (int i = 0; i < x; i++) {
  delete []mas[i];
}
delete []mas;
neske
1419 / 786 / 55
Регистрация: 26.03.2010
Сообщений: 2,694
16.04.2010, 19:40  [ТС]     Выделение динамической памяти для двумерного массива. #5
Проверил, работает, спасибо.
msangel
 Аватар для msangel
0 / 0 / 0
Регистрация: 10.03.2010
Сообщений: 13
04.05.2010, 07:21     Выделение динамической памяти для двумерного массива. #6
у меня встречный вопрос, чтоб уже добить эту тему:
освобождение правильное освобождение памяти:

у вашем примере вы освобождаете память с помощью такой конструкции:
C++
1
2
3
4
5
6
7
//----------------------------------------------------------------------------
//                      Выполняйте действия, которые вам необходимы
//--------------------------Освобождение памяти----------------------------
for (int i = 0; i < x; i++) {
  delete []mas[i];
}
delete []mas;
однако в учебнику пишут, что "Осводождение памяти из-под массива с любым количеством измерений с помощью операции delete[]"
Тоесть не надо делать то, что вы писали а достаточно только написать вот так:
C++
1
delete []mas;
???
easybudda
Модератор
Эксперт С++
 Аватар для easybudda
9373 / 5423 / 914
Регистрация: 25.07.2009
Сообщений: 10,423
04.05.2010, 09:14     Выделение динамической памяти для двумерного массива. #7
msangel, странный учебник. MiCr0s0fT правильно написал - по сути каждый элемент массива mas сам по себе является указателем на массив. И память для каждого из них была выделена оператором new[], соответственно должна быть возвращена оператором delete[]. Я в нескольких умных книжках читал, что возвращать нужно ровно столько памяти, сколько брал. И как-то такой подход кажется более правильным, чем упование на то, что для каждого элемента массива указателей mas сам собой оператор delete[] будет вызван, а не просто потеряется указатель на выделенную память. Кстати, а что за учебник?
msangel
 Аватар для msangel
0 / 0 / 0
Регистрация: 10.03.2010
Сообщений: 13
04.05.2010, 09:30     Выделение динамической памяти для двумерного массива. #8
что за учебник не скажу .

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

как узнать, что происходит утечка памяти?
MikeSoft
Эксперт C++
 Аватар для MikeSoft
3781 / 1765 / 85
Регистрация: 21.11.2009
Сообщений: 2,540
04.05.2010, 10:18     Выделение динамической памяти для двумерного массива. #9
msangel, easybudda, а я бы тоже не прочь узнать, что за учебник такой, кто так людей учит ... (судя по всему, обучалка для какой-нибудь современной IDE, где пользователь уже забыл, что значит "освободить память" - всё сделает машина)

И ещё интересно... а про обнуление в этом учебнике ничего не сказано?

Архангельский и Либерти, например, рекомендуют после высвобождения памяти производить обнуление значений. То есть, для примера:
C++
1
2
3
4
int *mas = new int [10];
// операции над массивом
delete []mas;
mas = NULL;
И вот что меня в этом удивило... Работаю в RAD Studio 2010.
У неё есть механизм анализа кода, который предупреждает, например, о том, что переменная была обьявлена, но нигде не использовалась...

Так вот, начинаю разработку проекта. Режим Debug.
Выделил память, попользовался ею, очистил. Обнулил. Компильнул - всё идеально.

Переключаюсь на Release.
Компилирую тот же код и получаю Warning'и в местах обнуления.
Предупреждение о том, что переменная больше нигде не используется.

Вот такие вот интересности из учебников...
easybudda
Модератор
Эксперт С++
 Аватар для easybudda
9373 / 5423 / 914
Регистрация: 25.07.2009
Сообщений: 10,423
04.05.2010, 11:16     Выделение динамической памяти для двумерного массива. #10
Цитата Сообщение от MiCr0s0fT Посмотреть сообщение
Архангельский и Либерти, например, рекомендуют после высвобождения памяти производить обнуление значений.
Ну в принципе-то правильно рекомендуют. Суть в том, что если в программе после того, как память была возвращена оператором delete / free и значение указателя установлено в NULL, пытаясь по ошибке использовать тот же указатель программа грохнется с исключением типа "NULL pointer bla bla bla...". А вот если указатель не был установлен в NULL, программа будет пытаться использовать уже не инициализированный участок памяти, и вот тут поведение её не предсказуемо. Так, что, это просто мера предосторожности такая, но вполне разумная...
MikeSoft
Эксперт C++
 Аватар для MikeSoft
3781 / 1765 / 85
Регистрация: 21.11.2009
Сообщений: 2,540
04.05.2010, 23:54     Выделение динамической памяти для двумерного массива. #11
easybudda, да, о мере предохранении от AV я осведомлён. Мне интересен сам факт, почему компилятор предупреждает о повторном использовании только что высвобожденного куска памяти. Не верится мне, что разработчики не учли случай "аккуратного" повторного использования того же участка памяти. (и именно в Release варианте сборки)
Возможно, существует какой-то другой рациональный метод ...
В данном случае мною движет чисто профессиональный интерес.
Завтра посмотрю, что скажет по этому поводу Visual Studio...
msangel
 Аватар для msangel
0 / 0 / 0
Регистрация: 10.03.2010
Сообщений: 13
05.05.2010, 00:35     Выделение динамической памяти для двумерного массива. #12
Не верится мне, что разработчики не учли случай "аккуратного" повторного использования того же участка памяти
у меня лично в 2008 студии возможно изменять и считывать переменные по адресу уже освобожденной памяти. разве память после удаления не перестает быть доступной?
а если остается доступной, то толку от этой чистки?

или может это потому, что оператор [] обеспечивает лиш доступ по смещению памяти и никаких проверок на доступность памяти не делает(в случае недоступности должна возбуздается ошыбка)
но ее нет и все работает
приведеный ниже код:

C++
1
2
3
4
    int *matr2 = new int [10];
    delete []matr2;
    matr2[15]=26;
    printf("%d",matr2[15]);
дает результат:
Код
26
Ни тут тебе проверок на доступность, ни на размер масива....
Почему так?
easybudda
Модератор
Эксперт С++
 Аватар для easybudda
9373 / 5423 / 914
Регистрация: 25.07.2009
Сообщений: 10,423
05.05.2010, 00:47     Выделение динамической памяти для двумерного массива. #13
MiCr0s0fT, я думаю - всё проще. При релизной сборке какой-нибудь варн-левел повышается, и компилятор отслеживает случаи, когда после последнего изменения значения переменной она нигде больше не используется. Наверное, это одно из множества параноидальных предупреждений, на которые можно просто внимание не обращать. Ну или отключить, чтоб граза не мозолило...
Вот к примеру код
C
1
2
3
4
5
6
7
#include <stdio.h>
 
int main(void){
    int i = 5;
    printf("Hello, world!\n");
    return 0;
}
а вот, что мелкомягкий cl пишет, если параметр Wall (включить все предупреждения) задать
Выделение динамической памяти для двумерного массива.
На собственные заголовочные файлы ругается. Что ж теперь, stdio.h "испралять"?
easybudda
Модератор
Эксперт С++
 Аватар для easybudda
9373 / 5423 / 914
Регистрация: 25.07.2009
Сообщений: 10,423
05.05.2010, 00:51     Выделение динамической памяти для двумерного массива. #14
msangel, попробуйте после
C++
1
delete []matr2;
добавить
C++
1
matr2 = NULL;
msangel
 Аватар для msangel
0 / 0 / 0
Регистрация: 10.03.2010
Сообщений: 13
05.05.2010, 01:07     Выделение динамической памяти для двумерного массива. #15
Цитата Сообщение от easybudda Посмотреть сообщение
msangel, попробуйте после
C++
1
delete []matr2;
добавить
C++
1
matr2 = NULL;
да, как я уже писал
оператор [] обеспечивает лиш доступ по смещению памят
поэтому естественно если нулевой адерес не может быть доступным, то и смещение невозможно отсчитать.
но вопрос как раз не в том.
вопрос состоит так:
должна возбуздается ошыбка
Ни тут тебе проверок на доступность, ни на размер масива
и все работает
разве память после удаления не перестает быть доступной?
mirso
523 / 341 / 17
Регистрация: 05.04.2009
Сообщений: 709
05.05.2010, 02:19     Выделение динамической памяти для двумерного массива. #16
msangel,
Цитата Сообщение от msangel Посмотреть сообщение
delete []matr2;
* * * * matr2[15]=26;
Еще прикольный вариант [-15]
C++
1
2
3
4
5
    int *matr2 = new int [1];
    delete []matr2;
    //matr2 = NULL;
    matr2[-15]=26;
    printf("%d\n",matr2[-15]);
Цитата Сообщение от msangel Посмотреть сообщение
Ни тут тебе проверок на доступность, ни на размер масива
msangel
 Аватар для msangel
0 / 0 / 0
Регистрация: 10.03.2010
Сообщений: 13
05.05.2010, 05:37     Выделение динамической памяти для двумерного массива. #17
да, это как минимум странно

я решил посмотреть как в таких случаях меняются адреса
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
    int *matr2 = new int [10];
    delete []matr2;
    //matr2 = NULL;
    printf("%d\n",matr2);
    matr2[-1]=26;
    printf("%d\n",matr2[-1]);
    printf("%d\n",&matr2[-1]);
    matr2[-2]=26;
    printf("%d\n",matr2[-2]);
    printf("%d\n",&matr2[-2]);
    matr2[1]=26;
    printf("%d\n",matr2[1]);
    printf("%n",&matr2[1]);
в результате у меня вишло -
C
1
2
3
4
matr2 = 3435312//адрес 0-го елемента
&matr2[1] = 3435316//адрес [1] елемента, что как видим на 4 больше чем у [0] т.е. sizeof(int)
&matr2[-1] = 3435308//адрес [-1] елемента, что как видим на 4 менше чем у [0]
&matr2[-2] = 3435304// еще на 4 менше
возникает следующие вопросы:
получается я могу розмещать в памяти за нужным мне адресом нужные объекты, если придумаю способ их сериализации в память?
конешно, возможно такой способ выделения памяти опасен тем, что приложение может по моих адресах разместить свои даные... хотя я об етом ничего не знаю...
как приложение управляет своей памятью? наверное у каждого приложения во время роботы создается таблица, где оно хранит используемые адреса, чтоб при динамичесском выделении памяти просто не писать поверх и указывать на свободные участки? возможно даже функции malloc/free и операторы new/delete и соответственно работают с такой таблицей?
или это в конце концов просто баг компилятора?

Добавлено через 22 минуты
да, я был прав
http://www.parashift.com/c++-faq-lit....html#faq-38.8
там написано об том, как выделяется динамеческая память

как я и предполагал - объекты пишутся прамо в память по смещению относительно указателя
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 // Original code: Fred* p = new Fred[n];
 Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
 size_t i;
 try {
   for (i = 0; i < n; ++i)
     new(p + i) Fred();           // Placement new
 }
 catch (...) {
   while (i-- != 0)
     (p + i)->~Fred();            // Explicit call to the destructor
   operator delete[] (p);
   throw;
 }
 arrayLengthAssociation.insert(p, n);
где p - собственно указатель и
for (i = 0; i < n; ++i)
new(p + i) Fred(); - запись одного елемента по смещению

но самое интерестное тут:
arrayLengthAssociation.insert(p, n);
в хелпе написано, что:
arrayLengthAssociation is the imaginary name of a hidden, global associative array that maps from void* to "size_t"
ну естественно тут непоказано алгоритмы для поиска свободного участка памяти через этот глобальный асоциативный масив, и установление указателя на эту область.

а в реализации все делается наоборот:
// Original code: delete[] p;
C++
1
2
3
4
size_t n = arrayLengthAssociation.lookup(p);
 while (n-- != 0)
   (p + n)->~Fred();
 operator delete[] (p);

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

Добавлено через 14 минут
нет
ну естественно тут непоказано алгоритмы для поиска свободного участка памяти через этот глобальный асоциативный масив, и установление указателя на эту область.
arrayLengthAssociation наверное работает только с количествами.
следовательно должен быть еще что-то, но уже с адресами

Добавлено через 23 минуты
так же было б интерестно узнать, как виделяется память под одну переменную\\
наверно программа просит об этом операционную систему
однако что то не могу найти таких исходников\\

Добавлено через 24 минуты
оу, уже нашел)))
http://en.wikipedia.org/wiki/Memory_pool
в ссилках под статьей интерестный исходник

и наверное выделеная таким образом память плюсуется к памяти приложения, расшыряя его адресное пространство
за это наверное тоже отвечают функции malloc/free и операторы new/delete - кроме всего они еще при необходимости запрашуют еще блок памяти или освобождают его))))

жаль, что передо мной не стоит задача написать собственный менеджер памяти, тут есть поле для творчества
fasked
Эксперт C++
 Аватар для fasked
4924 / 2504 / 180
Регистрация: 07.10.2009
Сообщений: 4,306
Записей в блоге: 1
05.05.2010, 08:01     Выделение динамической памяти для двумерного массива. #18
Цитата Сообщение от msangel Посмотреть сообщение
а в реализации все делается наоборот:
// Original code: delete[] p;
перегруженный оператор delete[] не расскажет тебе, как работает классический delete[]
msangel
 Аватар для msangel
0 / 0 / 0
Регистрация: 10.03.2010
Сообщений: 13
05.05.2010, 12:20     Выделение динамической памяти для двумерного массива. #19
перегруженный оператор delete[] не расскажет тебе, как работает классический delete[]
проблему собственно управлением памяти я затронул позже

тема же об
Выделение динамической памяти для двумерного массива.
и поетому я узнал, как работает удаление масива елементов
так как в даном примере в
C++
1
p
записан указатель на адрес начала масива объектов, то по сути по етому адресу записан масив указателей
поетому сначала удалаятся ппамять из под объектов, на которые ссылаются указатели:
C++
1
2
 while (n-- != 0)
   (p + n)->~Fred();
а уже потом собственно память из под самих указателей:
C++
1
operator delete[] (p);
я думаю, в реализации для одномернога масива базовых типов код выглядал бы так:
C++
1
2
3
size_t n = arrayLengthAssociation.lookup(p);
 while (n-- != 0)
   delete (p + n)
т.е. долхно выполнялоться как минимум 2 действия:
  • удаление информации о том, что память занимаема
  • собственно очистка памяти из под каждого элемента
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.05.2010, 12:27     Выделение динамической памяти для двумерного массива.
Еще ссылки по теме:

выделение динамической памяти для char C++
Как правильно записать в виде функции выделение памяти для двумерного массива и ее освобождение C++
C++ Выделение динамической памяти для массива точек

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
mirso
523 / 341 / 17
Регистрация: 05.04.2009
Сообщений: 709
05.05.2010, 12:27     Выделение динамической памяти для двумерного массива. #20
Цитата Сообщение от mirso Посмотреть сообщение
Еще прикольный вариант [-15]
Код C++
* * int *matr2 = new int [1];
* * delete []matr2;
* * //matr2 = NULL;
* * matr2[-15]=26;
Цитата Сообщение от msangel Посмотреть сообщение
да, это как минимум странно
Цитата Сообщение от msangel Посмотреть сообщение
как в таких случаях меняются адреса
msangel, они там точно прикалывались -> &(i[matr2])
C++
1
2
3
    for(int i = -15; i <= 15; ++i)
    printf("%3d) %10d | %#10x | %u\n", i, i[matr2], &(i[matr2]),
                (&(i[matr2]) -  &((i - 1)[matr2]) )*sizeof(matr2));
Yandex
Объявления
05.05.2010, 12:27     Выделение динамической памяти для двумерного массива.
Ответ Создать тему
Опции темы

Текущее время: 12:19. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru