C++中涉及新函数和删除[]函数的奇怪错误

Weird bug in C++ involving new and delete[] functions

本文关键字:函数 删除 错误 新函数 C++      更新时间:2023-10-16

我正在做Coursera算法的第一个编程作业:设计和分析课程(https://www.coursera.org/course/algo)。它涉及使用合并排序来计算反转(http://en.wikipedia.org/wiki/Inversion_(discrete_mathematics))。我认为这将是一个相对不费吹灰之力的事情,因为我以前(在学校)遇到过合并排序。

#include <iostream>
#include <fstream>
using namespace std;
int *half(int *array, int n, int start, int end)
{
    /*
     * Creates a new array which contains elements from ''array'' starting with ''start''
     * and ending with ''end - 1''.
     */
     int *new_array = new int[end-start];
     for(int i = start; i < end; i++)
     {
        new_array[i-start] = array[i];
     }
     return new_array;
}
int merge(int *array1, int n1, int *array2, int n2, int *new_array)
{
    /*
     *  Merges arrays 1 and 2 (with lengths n1 and n2) into a new_array, counting
     *  ''split inversions'' by the way.
     */
    int i = 0, j = 0, count = 0;
    for(int k = 0; k < n1 + n2; k++)
    {
         if(i >= n1)
        {
            new_array[k] = array2[j];
            j++;
            continue;
        }
         if(j >= n2)
        {
            new_array[k] = array1[i];
            i++;
            continue;
        }
        if( array1[i] <= array2[j] )
        {
            new_array[k] = array1[i];
            i++;
        }
        else
        {
            new_array[k] = array2[j];
            j++;
            count++;
        }
    }
    return count;
}
int mergesort(int *array, int n)
{
    if(n == 1) return 0; //base case
    int x, y, z;
    int odd;
    if(n%2 == 0) odd = 0;
    else odd = 1;
    int *half1 = new int [n/2];
    int *half2 = new int [n/2 + odd];
    half1 = half(array, n, 0, n/2);
    half2 = half(array, n, n/2, n);
    x = mergesort(half1, n/2);
    y = mergesort(half2, n/2 + odd);  //if n is odd, we add one
    z = merge(half1, n/2, half2, n/2 + odd, array); //we write a sorted array back in our starting array
    delete [] half1;
    delete [] half2;
    return x + y + z;
}
int main()
{
    int n;
    int *array = new int[n];
    cin >> n;
    for(int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        array[i] = x;
    }
    for(int i = 0; i < n; i++)
        cout << array[i] << " ";
    cout << endl;
    cout << "Number of inversions: " << mergesort(array, n) << endl;
    for(int i = 0; i < n; i++)
    cout << array[i] << " ";
    cout << endl;
    delete[] array;
    return 0;
}

那么,这里有什么奇怪的呢?第一件事:对我来说,它适用于某些数组,但对于其他数组会崩溃(稍后的示例)。第二件事:我把代码发给我的朋友,他说对他来说一切都很好,即使是对我来说急剧崩溃的例子。

所以,例子:

对于数组 [1 2 3 4 5 6 7] g++ 生成以下内容:

malloc.c:2451: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Aborted (core dumped)

当我使用 gdb"回溯"它时:

#0  0x00007ffff7753445 in __GI_raise (sig=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#1  0x00007ffff7756bab in __GI_abort () at abort.c:91
#2  0x00007ffff779abed in __malloc_assert (assertion=<optimized out>, file=<optimized out>, line=<optimized out>, function=<optimized out>) at malloc.c:300
#3  0x00007ffff779e0f4 in sYSMALLOc (av=0x7ffff7ad3720, nb=32) at malloc.c:2448
#4  _int_malloc (av=0x7ffff7ad3720, bytes=12) at malloc.c:3892
#5  0x00007ffff779fa45 in __GI___libc_malloc (bytes=12) at malloc.c:2924
#6  0x00007ffff7b8fded in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x00007ffff7b8ff09 in operator new[](unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#8  0x0000000000400b12 in mergesort (array=0x603010, n=7) at jedan.cpp:81
#9  0x0000000000400cfe in main () at jedan.cpp:120

它对数组 [1 2 3 4 5 6 7 8 9 10] 执行类似操作(但不相同!),再次连接到 new 和 delete[] 函数。如果有人认为这会有所帮助,我可以稍后在这里发布,但我不想过多地膨胀这篇文章。它适用于我尝试过的大多数数组(我对大小为 <= 6 的数组以及大量较大的数组都没有问题)。

我正在使用昨天安装的 Ubuntu 12.04...相当干净清新。帮助?

附言如果您发现变量名称有点奇怪,对不起...我从我的母语翻译了它们,这样代码就可以更具可读性。

int n;
int *array = new int[n]; // Undefined behavior

n在这里未初始化,因此您将获得"随机"长度分配。

如果你运气不好,并且n拥有"大"垃圾值,你的代码可能会看起来有效。如果它的值很小,则在填充初始数组时可能会损坏堆 - 这将产生您看到的错误类型。

cin >> n;行移动到array分配之前。

旁注:我认为您在mergesort中执行的两个分配被泄露了(您只是delete half中分配的内存,如果我正确阅读您的代码,您实际上不需要分配mergesort本身)。

你不检查

n==0

在 mergesort() 例程中。

然后 new[] 失败。

顺便说一句,half() 例程中的东西相同:

int *new_array = new int[end-start];

您不检查

end == start

您没有指定数组的数量:

int main()
{
    int n;
    int *array = new int[n];
    cin >> n;

程序启动时,您尚未指定 n 的值。 因此,分配的大小是未知的。

我建议在数组分配之前移动cin >> n;