【问题标题】:What difference between VC++ 2010 Express and Borland C++ 3.1 in compiling simple c++ code file?VC++ 2010 Express 和 Borland C++ 3.1 在编译简单的 c++ 代码文件上有什么区别?
【发布时间】:2012-05-18 09:26:11
【问题描述】:

我已经不知道该想什么或该做什么。下一个代码在两个 IDE 中都能正常编译,但在 VC++ 情况下,它会导致奇怪的堆损坏消息,例如:
"Windows 已在 Lab4.exe 中触发断点。

这可能是由于堆损坏,这表明 Lab4.exe 或其已加载的任何 DLL 中存在错误。

这也可能是由于用户在 Lab4.exe 获得焦点时按 F12。

输出窗口可能有更多诊断信息。”

它在执行 Task1_DeleteMaxElement 函数时发生,我将 cmets 留在那里。
如果在 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;
}

【问题讨论】:

  • Windows 提醒您有堆损坏错误,而不是 VS。 BC3 使用自己的堆分配器,因此 Windows 无法看到您的代码行为异常。以前没有注意到这些错误是非常了不起的,但并非完全不可能。
  • @Hans Passant:你确定 Windows 吗?我认为是 C/C++ 运行时检测到了这些错误……嗯……我想你是对的,但是,这意味着升级 Windows 版本很可能会导致之前没有发生过的崩溃一个应用程序...另一方面(我需要验证这一点),我通过mallocnew 有自己的分配器,这就是使用/MT 编译时无法解除分配的原因一个 DLL 中的指针,当它被分配到另一个 DLL 中时。

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


【解决方案1】:

我的猜测是 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 字节 = 1.25 int 当您期望 2 时(错误!)
  • 2 : 6 字节 = 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 迫使程序员修复他们的错误。不,Microsoft CRT 已经使用 HeapAlloc 实现 malloc/new 很长时间了。 Borland 有自己编写的历史,在 Windows 赶上之前击败了 Microsoft 一段时间。

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

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

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

【讨论】:

  • 是的,CRT 使用您描述的调试分配器,但它会生成不同的诊断。粗略地说,调试分配器捕获小错误,Windows 捕获大错误。
  • @Hans Passant:请您提供包含您的 cmets 的完整答案吗?我会将它们复制粘贴到我的答案中以供参考,但这确实感觉不对,因为 应该从这些知识中获益,而不是我。现在,我会将您的答案复制粘贴到我的评论中,一旦看到您的回答,我将用指向您答案的链接替换我复制/粘贴的 cmets。谢谢!
【解决方案2】:

如果它在 realloc 中崩溃了,那么你就超出了步进,malloc 和 free 的簿记记忆。

错误代码如下:

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 个字节,这会导致内存损坏并最终崩溃。

【讨论】:

    【解决方案3】:

    还有

    memcpy(arr, temp_arr, temp_arr_length);
    

    应该是

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

    【讨论】:

      猜你喜欢
      • 2011-05-16
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-19
      相关资源
      最近更新 更多