【问题标题】:Error while freeing memory allocated for sorted subarray in merge sort在合并排序中释放为排序子数组分配的内存时出错
【发布时间】:2015-04-10 22:52:49
【问题描述】:

我有下面的 merge_Sort() 函数,它实现了归并排序。

它确实排序正确(当我注释掉 free() 调用时),但是当我尝试释放已排序子数组占用的内存时就会出现问题。

/* merge_Sort() to merge array by didive and conquer*/
/* calls merge_v_1() to merge two sorted subarrays*/
/* merge_v_1() takes two sorted subarrays and copies them to new sorted array, and returns the pointer to this new sorted array*/
int *merge_Sort(int *array, int a, int b)
{
    if (a==b)
    return array;
   else
    {
         int middle = ((a+b)/2);
         int *left_Sub_Array, *right_Sub_Array;
         int *left_Sub_Array_1, *right_Sub_Array_1;

          left_Sub_Array = merge_Sort(array, a, middle);
          right_Sub_Array = merge_Sort((array + (middle - a + 1) ), middle + 1 ,b);

           left_Sub_Array_1 = left_Sub_Array;
           right_Sub_Array_1 = right_Sub_Array;

            int *newArray = malloc((b - a + 1) * (sizeof(int)));
            if (newArray == NULL)
             {
                  exit (1);
              }
             merge_v_1(left_Sub_Array_1, (middle - a + 1), right_Sub_Array_1, (b - middle), newArray);
         // PROBLEM IS HERE IN BELOW TWO FREE()
         free(left_Sub_Array);
         free(right_Sub_Array);
         return (newArray);
     }
}

最初,我认为这是因为函数 merge_v_1() 正在更改指针 left_Sub_Arrayright_Sub_Array。所以我想将left_Sub_Arrayright_Sub_Array的值复制到left_Sub_Array_1right_Sub_Array_1,然后将它们传递给merge_v_1(),这样left_Sub_Arrayright_Sub_Array的值就不会改变。但是,我在释放内存时遇到问题。

下面是一个示例输出。

user $ ./a.out
*** Error in `./a.out': free(): invalid pointer: 0x0000000002272014 ***
Aborted (core dumped)
user $ 

看起来我正在尝试释放我不应该释放的内存,但我无法找出根本原因。任何帮助表示赞赏。

【问题讨论】:

  • 为什么不创建一个与要排序的数组大小相同的新(单独)数组,并将其用作暂存空间?它节省了 malloc/free 的常量调用,节省了来回复制的时间,并且更易于理解和编程。

标签: c algorithm free mergesort


【解决方案1】:

您有 1 个 malloc 和 2 个 free。这总是一个问题。来自维基百科: http://en.wikipedia.org/wiki/C_dynamic_memory_allocation

动态内存分配的不当使用经常会成为错误的来源。这些可能包括安全漏洞或程序崩溃, 最常见的原因是分段错误。

最常见的错误如下:

不检查分配失败。内存分配不 保证成功,并且可能会返回一个空指针。如果 没有检查是否已实施成功分配,这通常 由于产生的分段导致程序崩溃 空指针取消引用的错误。内存泄漏。未能 使用 free 释放内存会导致不可重用内存的堆积, 程序不再使用它。这会浪费内存资源 当这些资源被占用时,可能会导致分配失败 累。逻辑错误。所有分配必须遵循相同的 模式:使用 malloc 分配,用于存储数据,解除分配 免费使用。未能遵守此模式,例如内存使用情况 在调用 free(悬空指针)之后或调用 malloc 之前 (野指针),调用 free 两次(“double free”)等,通常 导致分段错误并导致程序崩溃。 这些错误可能是暂时的且难以调试 - 例如,已释放 内存通常不会被操作系统立即回收,因此 悬空指针可能会持续一段时间并似乎可以工作。

我会检查你关于 newArray 的逻辑并摆脱第二个免费的。

【讨论】:

  • 一个malloc()是分配内存并返回指向newArray的指针。这个newArray 的值返回到left_Sub_Arrayright_Sub_Array。因此,当我在执行 free (left_Sub_Array) 或 free(right_Sub_Array) 时,我试图释放已执行并返回的合并函数的 newArray 指向的内存。每次我试图为新的排序数组分配内存(所以使用一个 malloc),然后将两个已经排序的数组合并到这个分配的内存中。然后我尝试free 旧的排序子数组。所以“两个”释放。所以这不是问题..
  • @sps 很确定。您没有显示 merge_v_1,但您应该在此处进行分配,将元素复制到新数组中,然后返回指针。然后你可以释放你的原始数组。祝你好运!!但正如 James T Smith 所说,更好的方法是根本不使用动态内存。
  • 是的,最后我改变了我的算法,现在我可以毫无问题地释放内存。我仍在使用动态内存,但在这里没有问题。但我仍然不确定为什么 OP 中的代码有问题。感谢您的关注和建议!
【解决方案2】:

内存分配很棘手,并且不能很好地与性能关键代码(如排序)混合使用。这是一个未排序数组的示例,其中包含用于临时存储的相应辅助数组。优势是 2 个 malloc,其次是 2 个 free。缺点是内存使用量是 2 倍。

// Code from Algorithms 4th edition - Robert Sedgewick, et al.
int main(void)
{
 int somearray[10];
 // fill with data
 int tmp_space[10];

 sort(somearray, tmp_space, 0, 9);
}


void merge(int *a, int *aux, int lo, int mid, int hi)
{
 int i = lo, j = mid+1, k;
 memcpy(&aux[lo], &a[lo], sizeof *a *((hi - lo) +1));

 // copied memory to auxiliary space. Now add back to real
 // space in proper order.
 for (k = lo; k <= hi; k++) {
  if (i > mid)
   a[k] = aux[j++];
  else if (j > hi)
   a[k] = aux[i++];
  else if (aux[j] < aux[i])
   a[k] = aux[j++];
  else
   a[k] = aux[i++];
 }
}

void sort(int *a, int *aux, int lo, int hi)
{
 if (hi <= lo) return;
 int mid = lo + ((hi - low)/2);

 // recursively break in half, and from the bottom up merge two halves.
 sort(a, aux, lo, mid);
 sort(a, aux, mid+1, hi);
 merge(a, aux, lo, mid, hi);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-20
    相关资源
    最近更新 更多