为什么点在释放时会崩溃?

时间:2019-08-06 02:37:33

标签: c heap heap-memory mergesort heap-corruption

在下面的代码中,结果没问题,但是代码在执行完成时将崩溃,并增加一个错误:检测到堆损坏,空闲列表在0x600000008f50处被破坏

int *mergeSort(int *a,int count) {

    int leftCount  = count / 2;
    int rightCount = count - leftCount;
    int *leftData  = getData(a, 0, leftCount);
    int *rightData = getData(a, leftCount, count);

    int *sortedLeftData  = mergeSort(leftData, leftCount);
    int *sortedRightData = mergeSort(rightData, rightCount);

    int *resultData = mergeData(sortedLeftData, sortedRightData, leftCount,
                                rightCount);

    return resultData;
}

int *getData(int *a,int from, int to) {

    if (from > to) { return nil; }
    int *res = malloc(to - from + 1);
    for (int index = from; index < to; index ++) {

        int value = a[index];
        res[index-from] = value;
    }
    return res;
}

int *mergeData(int *a, int *b, int acount, int bcount) {

    int *result = malloc(acount + bcount);

    int aindex,bindex,rindex;
    aindex = bindex = rindex = 0;

    while (aindex < acount | bindex < bcount) {

        int value,avalue = INT_MAX,bvalue = INT_MAX;
        if (aindex < acount) { avalue = a[aindex]; }
        if (bindex < bcount) { bvalue = b[bindex]; }
        // get value from a point.
        if (avalue <= bvalue) {

            value = avalue;
            aindex ++;
        }else {
            // get value from b point.
            value = bvalue;
            bindex ++;
        }

        result[rindex] = value;
        rindex ++;
    }

    return result;
}

我不明白为什么在释放积分时会崩溃,任何答案都会有所帮助,谢谢。

2 个答案:

答案 0 :(得分:2)

所有分配都太小,因此缓冲区溢出。

malloc函数分配请求的 bytes 个字节。如果您的元素是sizeof(int)类型,则需要将所需的元素数乘以int例如

int *result = malloc((acount + bcount) * sizeof(int));

我在阅读代码时发现的其他潜在问题是:

  1. 使用按位或运算符代替逻辑或:

    while (aindex < acount | bindex < bcount)
                        // ^ should be ||
    
  2. 您永远不会释放临时缓冲区,因此您的程序将因疯狂泄漏而耗尽内存。完成操作后,必须在leftData函数中释放rightDatasortedLeftDatasortedRightDatamergeSort

    请注意,合并排序实际上不需要太多分配。这样做将对性能产生巨大影响。一个有效的实现只需要一个用于暂存操作的附加缓冲区,就可以在开始时分配它。

答案 1 :(得分:0)

我的实现合并排序使用单个缓冲区,如下代码:

void mergeSort(int *a, int count) {

    int *tempBuffer = malloc(count * sizeof(int));
    mergeSortWithBuffer(a, 0, 0, count - 1,tempBuffer);
    free(tempBuffer);
}
void mergeSortWithBuffer(int *a, int leftStart, int rightStart, int end, int *tempBuffer) {

    int leftCount  = rightStart - leftStart;
    int rightCount = end - rightStart + 1;
    if (leftCount + rightCount <= 1) { return; }

    if (leftCount != 0) {

        // left dichotomy
        int lls = leftStart;
        int lrs = leftStart + leftCount/2;
        int lnd = rightStart - 1;
        mergeSortWithBuffer(a, lls, lrs, lnd,tempBuffer);
    }

    if (rightCount != 0) {

        // right dichotomy
        int rls = rightStart;
        int rrs = rightStart + rightCount/2;
        int rnd = end;
        mergeSortWithBuffer(a, rls, rrs, rnd,tempBuffer);
    }

    mergeData(a, leftStart, rightStart, end, tempBuffer);
}

void mergeData(int *a, int leftStart, int rightStart, int end,int *tempBuffer) {

    int leftCount  = rightStart - leftStart;
    int rightCount = end - rightStart + 1;

    int lindex,rindex;
    lindex = rindex = 0;

    while (lindex < leftCount || rindex < rightCount) {

        int lv = INT_MAX,rv = INT_MAX;
        if (lindex < leftCount) { lv = a[leftStart + lindex]; }
        if (rindex < rightCount) { rv = a[rightStart + rindex]; }

        if (lv <= rv) {

            tempBuffer[leftStart + lindex + rindex] = lv;
            lindex ++;
        }else {

            tempBuffer[leftStart + lindex + rindex] = rv;
            rindex ++;
        }
    }

    for (int index = 0; index < end - leftStart + 1; index ++) {

        a[leftStart + index] = tempBuffer[leftStart + index];
    }
}

我认为mergeData函数可以在没有临时缓冲区的情况下互相替换数据,但是逻辑过于复杂且效率不高,因此我在此函数中添加了临时缓冲区。

如果愿意,您有更好的建议吗?