0

MVC++ 2010 の c++ でコードを作成しました。その中で、プログラムは 1 次元ポインター配列 (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)、プログラムは動作を停止します!

4

3 に答える 3

3

最も可能性の高い説明は、スタックスペースが不足していることです。簡単な修正は、配列を静的またはグローバルにすることです。newfrom heapで割り当てることもできます。どちらも配列をスタックの外に移動します。

最善の方法は、おそらくスマート ポインターを使用してヒープに配置することです。

std::unique_ptr<double[]> arrayOfDoubles(new double[size]);

これにより、スマート ポインター変数がスコープ外になったときにメモリが解放されます。手動で削除する必要はありません。

より良い答えを得るには、質問を編集してコードを含めます...


追加したコードには、少なくとも配列のインデックス付けに問題があります。インデックスは 0 から始まり、配列サイズから 1 を引いた値までです。正しいループ:

double *T = new double[I * J];
for (int r = 0; r < I * J; ++r)
    T[r] = 100;

他のループでも同じエラーが発生します。同じ修正です。

代替修正: 1 からインデックス付けを開始する場合 (同様に、そのように記述された疑似コード アルゴリズムがあり、インデックス付けを変更したくないため)、最も簡単な方法は、1 つの大きな配列を割り当て、インデックス 0 を使用しないことです。

double *T = new double[I * J + 1];

これで、現在のループを使用できます。


このような 1 つの配列要素によるバッファ オーバーランは厄介です。割り当てられたメモリ ブロックの最後に未使用のスペースが存在することがよくあるため、配列のサイズを変更して未使用のスペースがなくなるまで、バグはまったく気付かれない可能性があります。また、オーバーランによってヒープが破損したとしても、コードを変更して破損の影響が変わるまで、気付かないことがあります。たとえば、運が悪い場合は、デバッグ コードを追加すると問題が隠れる可能性があります。

于 2013-04-20T18:43:50.353 に答える
2

スタックに割り当てたスペースが多すぎるため、要求を満たすのに十分なメモリがありません。別の方法として、オブジェクトに静的ストレージ期間を指定するか、次の方法でフリー ストアに置くことができますnew

std::unique_ptr<int[]> ptr(new int[size]);
于 2013-04-20T18:53:52.353 に答える
2

次のように、スタックにプレーンな配列を割り当てているようです。

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

スタックのサイズは限られてnewいますstd::vector

于 2013-04-20T18:44:15.163 に答える