【问题标题】:Manipulating a global array in a recursive function在递归函数中操作全局数组
【发布时间】:2014-05-19 14:49:37
【问题描述】:

我正在研究一种算法 MOOC,并且有一个小程序,它以任意顺序获取一个整数数组 A,计算反转的数量(反转是数组索引的对数 (i,j)i<jA[i] > A[j])。

下面是我写的代码。我正在尝试使用“分而治之”的方法来解决它,我们递归地将输入数组分成两半,在计算反转时分别对每一半进行排序,然后合并两半。

诀窍是我需要跟踪反转的次数对数组进行排序,所以我将原始数组作为参数传递给函数并传递给函数的各种递归调用反转作为返回值。

代码通过连续划分和排序 [1,5,3] 的第一组递归调用正确执行,但是当我第三次调用 mergeAndCountSplitInv 时,它在该行崩溃:

sortedArrayLeft = realloc(sortedArrayLeft, sizeof(int)*(rightLen + leftLen));

出现错误:

malloc: *** error for object 0x100103abc: pointer being realloc'd was not allocated

我看不到我没有正确使用 malloc 的地方,我已经梳理了这个检查以查看我正在正确地进行指针运算并且无法发现任何错误,但显然存在错误。

感谢任何帮助。

//  main.c
//  inversionInC

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

// function to help with debugging array/pointer arithmetic
void logArrayLenAndContents (char *arrayName, int arrayToPrint[], int arrayLen){
    printf("%s\n", arrayName);
    printf("len:%d\n", arrayLen);
    for (int idx = 0; idx < arrayLen; idx++) {
        printf("array[%d]: %d\n", idx, arrayToPrint[idx]);
    }
}

int mergeAndCountSplitInv(int sortedArrayLeft[], int leftLen, int sortedArrayRight[], int rightLen)
{
    printf("Calling mergeAndCount with sortedArrayLeft:\n");
    logArrayLenAndContents("left Array", sortedArrayLeft, leftLen);
    printf("...and sortedArrayRight:\n");
    logArrayLenAndContents("right Array", sortedArrayRight, rightLen);

    int i = 0;
    int j = 0;
    int k = 0;
    int v = 0; // num of split inversions

    int* outArray;
    outArray = malloc((leftLen + rightLen) * sizeof(int));

    while (i < leftLen && j < rightLen) {
        if (sortedArrayLeft[i] < sortedArrayRight[j]) {
            outArray[k] = sortedArrayLeft[i];
            i++;
        } else{
            outArray[k] = sortedArrayRight[j];
            v += leftLen - i;
            j++;
        }
        k++;
    }
    // if at the end of either array then append the remaining elements
    if (i < leftLen) {
        while (i < leftLen) {
            outArray[k] = sortedArrayLeft[i];
            i++;
            k++;
        }
    }

    if (j < rightLen) {
        while (j < rightLen) {
            outArray[k] = sortedArrayRight[j];
            j++;
            k++;
        }
    }

    printf("Wrapping up mergeAndCount where outArray contains:\n");
    logArrayLenAndContents("outArray", outArray, k);

    sortedArrayLeft = realloc(sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
    return v;
}

int sortAndCount(int inArray[], int inLen){
    printf("Calling sortAndCount with:\n");
    logArrayLenAndContents("inArray", inArray, inLen);

    if (inLen < 2) {
        return 0;
    }

    int inArrayLenPart1 = ceil(inLen/2.0);
    int inArrayLenPart2 = inLen - inArrayLenPart1;

    int* rightArray = malloc(sizeof(int) * inArrayLenPart2);
    rightArray = &inArray[inArrayLenPart1];

    int x = sortAndCount(inArray, inArrayLenPart1);
    printf("sortAndCount returned x = %d\n\n", x);
    int y = sortAndCount(rightArray, inArrayLenPart2);
    printf("sortAndCount returned y = %d\n\n", y);

    int z = mergeAndCountSplitInv(inArray, inArrayLenPart1, rightArray, inArrayLenPart2);
    printf("mergeAndCount returned z = %d\n", z);
    return x+y+z;
}

int main(int argc, const char * argv[])
{
    static int* testArray;
    testArray = malloc(5 * sizeof(int));
    for (int i = 0; i<=4; i++) {
        testArray[0] = 1;
        testArray[1] = 5;
        testArray[2] = 3;
        testArray[3] = 2;
        testArray[4] = 4;
    }

    int x = sortAndCount(testArray, 5);
    printf("x = %d\n", x);
    return 0;
}

【问题讨论】:

  • int* rightArray = malloc(sizeof(int) * inArrayLenPart2);rightArray = &amp;inArray[inArrayLenPart1]; :错误。 rightArray 被 inArray 的一部分重写。它不是 malloced 地址(不是 malloc 的返回,所以不能重新分配)。
  • 注意:你让这变得困难了。计数反转的逻辑是正确的(右分区值与左中元素的距离)。但是您应该知道您不需要重新分配或本地分配合并空间。非就地合并排序(实际上就是这样)对于 N 个元素只需要 N 个临时空间,而创造性的参数传递算法和指针算法将通过 one 分配来完成这项工作一开始。 See it live,祝你好运。
  • @WhozCraig 顺便说一句,您在第 25 行和第 26 行复制剩余元素的方式非常聪明。再次感谢您。
  • @Nick 如果您在 C++ 中执行此操作,请不要尝试使用除 POD 类型之外的任何内容。在这种情况下使用std::copy(尽管如果您关心的只是反转检测,对指针数组进行排序并且在这种情况下保持对象向量不变)。很高兴你能从中得到一些用处。

标签: c arrays pointers recursion


【解决方案1】:

这是因为sortedArrayLeft 的值在函数返回后立即丢失。重新分配的值不会传递给调用者,因此如果realloc 需要重新分配和复制,sortAndCount 中的inArray 可能指向已释放的内存。

为了解决这个问题,将指针传递给指针,让sortedArrayLeft 传播回sortAndCountinArray

int mergeAndCountSplitInv(int **sortedArrayLeft, int leftLen, int sortedArrayRight[], int rightLen) {
    ...
    *sortedArrayLeft = realloc(*sortedArrayLeft, sizeof(int)*(rightLen + leftLen));
    return v;
}
...
int sortAndCount(int **inArray, int inLen) {
    ...
    int z = mergeAndCountSplitInv(inArray, inArrayLenPart1, rightArray, inArrayLenPart2);
}
...
int x = sortAndCount(&testArray, 5);

【讨论】:

    猜你喜欢
    • 2016-02-01
    • 2014-07-26
    • 2014-11-16
    • 1970-01-01
    • 2018-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    相关资源
    最近更新 更多