0

私はすでに何を考え、何をすべきかわかりません。次のコードは両方のIDEで正常にコンパイルされますが、VC ++の場合、次のような奇妙なヒープ破損メッセージが表示されます。
「WindowsがLab4.exeでブレークポイントをトリガーしました。

これは、ヒープの破損が原因である可能性があります。これは、Lab4.exeのバグを示しています。またはロードされたDLLのいずれか。

これは、Lab4.exeにフォーカスがあるときにユーザーがF12を押したことが原因である可能性もあります。

出力ウィンドウには、より多くの診断情報が表示される場合があります。」

Task1_DeleteMaxElement関数を実行すると発生し、コメントを残します。
Borland C ++ 3.1でコンパイルされ、すべてが期待どおりに機能する場合、そのようなことは起こりません。

だから...私のコードまたはVC++の何が問題になっていますか?

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <memory.h>

void PrintArray(int *arr, int arr_length);
int Task1_DeleteMaxElement(int *arr, int arr_length);

int main()
{
    int *arr = NULL;
    int arr_length = 0;

    printf("Input the array size: ");
    scanf("%i", &arr_length);

    arr = (int*)realloc(NULL, arr_length * sizeof(int));

    srand(time(NULL));

    for (int i = 0; i < arr_length; i++)
        arr[i] = rand() % 100 - 50;

    PrintArray(arr, arr_length);

    arr_length = Task1_DeleteMaxElement(arr, arr_length);

    PrintArray(arr, arr_length);

    getch();

    return 0;
}

void PrintArray(int *arr, int arr_length)
{
    printf("Printing array elements\n");

    for (int i = 0; i < arr_length; i++)
        printf("%i\t", arr[i]);

    printf("\n");
}

int Task1_DeleteMaxElement(int *arr, int arr_length)
{
    printf("Looking for max element for deletion...");

    int current_max = arr[0];

    for (int i = 0; i < arr_length; i++)
        if (arr[i] > current_max)
            current_max = arr[i];

    int *temp_arr = NULL;
    int temp_arr_length = 0;

    for (int j = 0; j < arr_length; j++)
        if (arr[j] < current_max)
        {
            temp_arr = (int*)realloc(temp_arr, temp_arr_length + 1 * sizeof(int)); //if initial array size more then 4, breakpoint activates here
            temp_arr[temp_arr_length] = arr[j];
            temp_arr_length++;
        }


    arr = (int*)realloc(arr, temp_arr_length * sizeof(int));
    memcpy(arr, temp_arr, temp_arr_length);
    realloc(temp_arr, 0); //if initial array size is less or 4, breakpoint activates at this line execution

    return temp_arr_length;
}
4

3 に答える 3

3

私の推測では、VC ++ 2010はメモリの破損を正しく検出していますが、これはBorland C++3.1では無視されます。

それはどのように機能しますか?

たとえば、メモリを割り当てる場合、VC ++ 2010のreallocは、その周囲のメモリに特別な値を「マーク」することができます。これらの値を上書きすると、reallocは破損を検出してから、クラッシュします。

Borland C++3.1で動作するという事実は純粋な運です。これは非常に古いコンパイラ(20年!)であるため、この種のメモリの破損に対してより寛容/無知になります(アプリでランダムで明らかに無関係なクラッシュが発生するまで)。

コードの何が問題になっていますか?

エラーの原因:

temp_arr = (int*)realloc(temp_arr, temp_arr_length + 1 * sizeof(int))

次のtemp_arr_length値の場合、32ビットでは、割り当ては次のようになります。

  • 0:1(Ok)を期待する場合は4バイト= 1 int
  • 1:2を期待する場合は5バイト= 1.25 int(エラー!)
  • 2:3を期待する場合は6バイト= 1.5 int(エラー!)

あなたはあなたの優先順位を間違えました。ご覧のように:

temp_arr_length + 1 * sizeof(int)

代わりにすべきです

(temp_arr_length + 1) * sizeof(int)

割り当てられたメモリが少なすぎるため、割り当てられたメモリをはるかに超えて書き込みました。

編集(2012-05-18)

ハンス・パッサントはアロケータの診断についてコメントしました。彼が彼自身の答えを書くまで、私はここでそれらをコピーする自由を取りました(私はすでにコメントがSOで消えるのを見ました):

VSではなくヒープ破損のバグがあることを思い出させるのはWindowsです。BC3は独自のヒープアロケータを使用するため、Windowsはコードの誤動作を認識できません。以前にこれらのバグに気づかなかったことはかなり注目に値しますが、完全に不可能というわけではありません。

[...]この機能はXP以前では使用できません。そして確かに、誰もがVistaについて愚痴を言った理由の1つです。プログラムの実際のバグについてOSを非難します。Win7は、Vistaがプログラマーにバグの修正を強制したため、少なからず「より優れた」OSとして認識されています。いいえ、MicrosoftCRTは長い間HeapAllocでmalloc/newを実装してきました。Borlandには、Windowsが追いつくまでしばらくの間、Microsoftを打ち負かして、独自に作成した歴史がありました。

[...] CRTは、説明したようなデバッグアロケータを使用しますが、異なる診断を生成します。大まかに言って、デバッグアロケータは小さな間違いをキャッチし、Windowsは重大なミスをキャッチします。

割り当て/割り当て解除の前後にWindows/CRTアロケータによってメモリに対して行われることを説明する次のリンクを見つけました。

最後のリンクには、私が印刷したテーブルが含まれており、常に私の近くにあります(これは、最初の2つのリンクを見つけるときに探していたこのテーブルです...:-...)。

于 2012-05-18T09:37:05.530 に答える
1

それがreallocでクラッシュしている場合、あなたはステップオーバーであり、本はmallocのメモリを保持し、無料です。

間違ったコードは次のとおりです。

temp_arr = (int*)realloc(temp_arr, temp_arr_length + 1 * sizeof(int));

する必要があります

temp_arr = (int*)realloc(temp_arr, (temp_arr_length + 1) * sizeof(int));

演算子の優先順位が*over+であるため、reallocが8バイトを渡すことを期待しているループの次の実行では、5バイトしか渡さない可能性があります。したがって、2回目の反復では、他の誰かのメモリを3バイトに書き込むことになります。これにより、メモリが破損し、最終的にクラッシュします。

于 2012-05-18T09:37:36.457 に答える
1

また

memcpy(arr, temp_arr, temp_arr_length);

する必要があります

memcpy(arr, temp_arr, temp_arr_length * sizeof(int) );
于 2012-05-18T09:44:54.007 に答える