Я написал код на C ++ в MVC ++ 2010. Внутри него программа перебирает элементы массива 1-D указателей (double *). Однако, когда я делаю ввод (размер массива указателей) очень большим, например, 15000, и запускаю программу, он перестает работать и показывает окно для закрытия программы, поскольку она не отвечает! В чем проблема?
Вот часть кода, который создает массив, о котором я говорю:
map<int, double *> CF;
CoefficientMap(CF);
double *T = new double[I * J];
for (int r = 1; r <= I * J; ++r)
T[r] = 100;
SOR(T, CF, 1.8);
а вот итераторная функция:
void SOR(double *T, map<int, double *> &CF, double w)
{
int iter = 0;
cout << "Stage 2: Solving the linear system of equations using SOR method... ";
const double tol = 0.00001;
double error = tol + 1;
double *TOld = new double[I * J];
for (int i = 1; i <= I * J; ++i)
TOld[i] = 100;
while (abs(error) > tol)
{
++iter;
for (int i = 1; i <= I * J; ++i)
T[i] = (CF[i][0] + CF[i][1] * T[i + 1] + CF[i][2] * T[i + J] + CF[i][3] * T[i - J] + CF[i][4] * T[i - 1]) * w + (1 - w) * T[i];
error = errorCalc(TOld, T, I * J);
for (int i = 1; i <= I * J; ++i)
TOld[i] = T[i];
if (iter % 100 == 0)
{
cout << endl << endl;
cout << "100 iterations done, please wait..." << endl << "Total accumulative error till this point: " << error << endl;
}
if (iter > 10000)
return;
}
cout << "Done!" << endl << endl;
cout << "Converged after " << iter << " iterations!" << endl;
cout << "Final accumulative error: " << error << endl << endl;
}
Теперь, когда (I * J) становится достаточно большим (например, 15000), программа перестает работать!
Скорее всего, объяснение состоит в том, что вы исчерпали пространство стека. Простое решение — сделать массив статическим или глобальным. Вы также можете выделить его new
из кучи. Оба перемещают массив из стека.
Лучше всего использовать умный указатель и поместить его в кучу:
std::unique_ptr<double[]> arrayOfDoubles(new double[size]);
Это позаботится об освобождении памяти, когда переменная интеллектуального указателя выйдет из области видимости, не нужно удалять вручную.
Для лучшего ответа отредактируйте вопрос так, чтобы он содержал код …
Ваш добавленный код имеет по крайней мере проблему с индексацией массива. Индексы начинаются с 0 и переходят к размеру массива минус один. Правильный цикл:
double *T = new double[I * J];
for (int r = 0; r < I * J; ++r)
T[r] = 100;
У вас такая же ошибка в других циклах, то же самое исправление.
Альтернативное исправление: если вы хотите начать индексирование с 1 (например, поскольку у вас есть алгоритм псевдокода, написанный таким образом, и вы не хотите изменять индексирование), проще всего выделить один больший массив и не использовать индекс 0:
double *T = new double[I * J + 1];
С этим вы можете использовать ваши текущие петли.
Такие переполнения буфера одним элементом массива являются мерзкими, потому что часто в конце выделенного блока памяти может быть неиспользуемое пространство, поэтому ошибка может остаться совершенно незамеченной, пока вы не измените размер массива и не исчезнет неиспользуемое пространство. И даже если переполнение приводит к повреждению кучи, оно может остаться незамеченным до тех пор, пока вы не измените код и не изменится эффект повреждения. Так, например, добавление кода отладки может скрыть проблему, если вам не повезло.
Похоже, вы выделяете простой массив в стеке, например так:
void f()
{
double a[123456];
...
}
Размер стека ограничен — вы должны выделить new
или (лучше) использовать std::vector
,
Вы выделили слишком много места в стеке, поэтому недостаточно памяти для выполнения вашего запроса. В качестве альтернативы вы можете указать статический срок хранения объекта или поместить его в бесплатное хранилище с помощью new
:
std::unique_ptr<int[]> ptr(new int[size]);