在编译简单的c ++代码文件时VC ++ 2010 Express和Borland C ++ 3.1有什么区别?

时间:2012-05-18 09:26:12

标签: visual-c++ c++builder breakpoints heap-memory

我已经不知道该怎么想或该怎么做了。下一个代码在两个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;
}

3 个答案:

答案 0 :(得分: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:4 bytes = 1 int当你期望1(Ok)
  • 1:5 bytes = 1.25 int,当你期望2(错误!)
  • 2:6 bytes = 1.5 int当你期望3(错误!)

你的嫌疑人错了。如你所见:

temp_arr_length + 1 * sizeof(int)

应该是

(temp_arr_length + 1) * sizeof(int)

你分配的内存太少,因此写得远远超出为你分配的内容。

编辑(2012-05-18)

Hans Passant评论了分配器诊断。我冒昧地把它们复制到这里,直到他写下自己的答案(我已经看到了消失在SO上):

  

Windows 提醒您有堆损坏错误,而不是VS. BC3使用自己的堆分配器,因此Windows无法看到您的代码错误行为。之前没有注意到这些错误是非常了不起的,但并非完全不可能。

     

[...]此功能在XP及更早版本中不可用。当然,这也是每个人都对Vista嗤之以鼻的原因之一。责怪操作系统实际上是程序中的错误。 Win7被认为是一个“更好”的操作系统,因为Vista迫使程序员修复他们的错误。不,微软CRT已经用HeapAlloc实现了malloc / new很长一段时间。 Borland有自己的写作历史,在Windows陷入困境之前一直击败微软。

     

[...] CRT使用您描述的调试分配器,但它会生成不同的诊断。粗略地说,调试分配器捕获了小错误,Windows捕获了大量错误。

我发现以下链接解释了分配/解除分配之前和之后Windows / CRT分配器对内存所做的操作:

最后一个链接包含我打印的表格,并且总是在我附近工作(这是我在寻找前两个链接时搜索的表...: - ...)。

答案 1 :(得分:1)

如果它在realloc中崩溃,那么你就过度踩踏了,这本书记住了malloc&amp;免费。

错误代码如下:

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

应该是

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

由于*的运算符优先级超过+,因此在期望realloc传递8个字节时,在循环的下一次运行中,它可能只传递5个字节。因此,在第二次迭代中,您将写入3个字节的别人的内存,这会导致内存损坏并最终崩溃。

答案 2 :(得分:1)

另外

memcpy(arr, temp_arr, temp_arr_length);

应该是

memcpy(arr, temp_arr, temp_arr_length * sizeof(int) );