#c #arrays #function #memory-management
#c #массивы #функция #управление памятью
Вопрос:
Я хочу передать массив определенной функции на c . Я написал следующий код:
#define nmpart 50
void distances( double (amp;dis)[3][nmpart][nmpart] )
{
... compute distances which are allocated in "dis"
}
double energy()
{
double dis[3][nmpart][nmpart];
distances(dis);
}
Этот код работает нормально, когда nmpart<800 примерно. Проблема в том, что я хотел бы
чтобы иметь больший массив, допустим, для nmpart = 50000. Я прочитал на этом форуме, что
для решения этой проблемы можно использовать динамическое распределение. Мне непонятно, как можно
В этой ситуации я использую динамическое распределение. Не могли бы вы дать мне несколько советов.
Комментарии:
1. Вы уверены, что вам нужен массив такого размера? Когда nmpart = 50000, у вас будет 50000*50000*3* размер (double), который будет равен 60 ГБ. Использование динамического распределения только ухудшит ситуацию, поскольку потребует дополнительного пространства для управляющих структур. Если массив заполнен только частично, то лучше использовать разреженный массив. Если нет, возможно, ваш алгоритм можно изменить, чтобы вычислять расстояния по требованию.
Ответ №1:
Многие люди (включая меня) никогда бы не написали этот код профессионально (или как-то иначе), но в основном он отвечает на ваш вопрос. Смотрите ниже, почему я бы никогда не написал это профессионально.
#define nmpart 50
void distances( const double ***dist)
{
... compute distances which are allocated in "dis"
}
double energy()
{
double ***dis;
// allocate dis
dis = new double**[3];
for(int i=0;i<3; i)
{
dis[i] = new double*[nmpart];
for(int j=0;j<nmpart; j)
{
dis[i][j] = new double[nmpart];
}
}
// code where you populate dis
// HERE
distances(dis);
// deallocate dis
for(int i=0;i<3; i)
{
for(int j=0;j<nmpart; j)
{
delete [] dis[i][j];
}
delete [] dis[i];
}
delete [] dis;
}
В принципе, я бы никогда не написал это (кроме как в учебных целях), потому что, если где-то в этой функции возникнет исключение, то произойдет утечка памяти. Лучше всего было бы обернуть выделения кучи и освобождения (с new
и delete
соответственно) в класс и поместить этот класс в локальный стек внутри вашей energy()
функции.
В идеале вы должны сделать что-то вроде этого:
#define nmpart 50
void distances( const distClass amp;dis)
{
... compute distances which are allocated in "dis"
}
double energy()
{
distClass dis;
// this allocate wraps the for loops with the new []'s above
dis.Allocate(3, nmpart , nmpart);
// populate dis HERE
distances(dis);
// when dis goes out of scope its destructor
// is called, which wraps the for loops with the delete []'s
}
Ответ №2:
Вместо этого вы можете использовать std::vector. Это позволяет выполнять динамическое распределение.
void distances( std::vector< std::vector< std::vector<double> > > constamp; dis )
{
... compute distances which are allocated in "dis"
}
double energy()
{
std::vector< std::vector< std::vector<double> > > dis;
distances(dis);
}
Комментарии:
1. как я мог бы настроить размер массива [3][nmpart][nmpart] с использованием std::vector?
2. Хм … хотя технически это динамическая версия вопроса OP, я бы сказал, что любое решение, которое включает вектор векторов векторов, немного нарушено 🙂 Как насчет одного массива или вектора, доступ к которому осуществляется за несколько шагов?
3. вы можете использовать dis.resize(3) для первого элемента, затем выполнить цикл над второй частью с помощью for (i=0;i Это выглядит ужасно. Поэтому предложение Kerrek SB использовать один массив, который сохраняет данные последовательно, может быть лучше. Как можно создать код в комментариях?
4. @Kerrek SB, я не спорю, но почему вы считаете любое решение, которое включает в себя вектор векторов, нарушенным?
5. @ChrisA.: Это просто слишком сложно. Такое большое выделение не может быть полезным. Плоский вектор, к которому обращаются шагами, дает вам гораздо лучшую локальность памяти и меньшее количество выделений.