Visual C ++ программа перестает работать, когда размер массива слишком велик

Я написал код на 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), программа перестает работать!

0

Решение

Скорее всего, объяснение состоит в том, что вы исчерпали пространство стека. Простое решение — сделать массив статическим или глобальным. Вы также можете выделить его 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];

С этим вы можете использовать ваши текущие петли.


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

3

Другие решения

Похоже, вы выделяете простой массив в стеке, например так:

void f()
{
double a[123456];
...
}

Размер стека ограничен — вы должны выделить new или (лучше) использовать std::vector,

2

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

std::unique_ptr<int[]> ptr(new int[size]);
2
По вопросам рекламы [email protected]