代码的工作原理大致如下: 在输入中给出一个矩阵及其列和行的值,该算法搜索最短路径,优先 Select 某些单元格继续前进.

下面是我正在讨论的代码的一部分:

/* Function to find the sh或test path in the matrix using BFS */
void findSh或testPath(Matrix *matrix, Result *bestResult) {
    int numRows = matrix->rows;
    int numCols = matrix->cols;
    int **visited = (int **)malloc(numRows * sizeof(int * ));
    int i, newDistance, newBadCells, newNegativeCells, row, col, distance, badCells, negativeCells;
    int dx[] = {
        -1,
        1,
        0,
        0
    };
    int dy[] = {
        0,
        0,
        -1,
        1
    };
    BFSNode currentNode;
    BFSNode *queue = (BFSNode *)malloc(numRows * numCols * sizeof(BFSNode));
    int queueSize = 0;
    char *path;
    char *check = "";

    f或 (i = 0; i < numRows; i++) {
        visited[i] = (int *)malloc(numCols * sizeof(int));
        memset(visited[i], 0, numCols * sizeof(int));
    }

    enqueue(queue, &queueSize, createBFSNode(0, 0, 0, 0, 0, ""));

    while (queueSize > 0) {
        qs或t(queue, queueSize, sizeof(BFSNode), pri或ityCompare);

        currentNode = dequeue(queue, &queueSize);
        row = currentNode.point.row;
        col = currentNode.point.col;
        distance = currentNode.distance;
        badCells = currentNode.badCells;
        negativeCells = currentNode.negativeCells;
        path = currentNode.path;

        if (row == numRows - 1 && col == numCols - 1) {
            if (bestResult->distance == -1 || distance < bestResult->distance) {
                bestResult->distance = distance;
                bestResult->badCells = badCells;
                bestResult->negativeCells = negativeCells;
                free(bestResult->path);
                bestResult->path = strdup(path);
            } else if (distance == bestResult->distance && negativeCells > bestResult->negativeCells) {
                bestResult->badCells = badCells;
                bestResult->negativeCells = negativeCells;
                free(bestResult->path);
                bestResult->path = strdup(path);
            }

            continue;
        }

        visited[row][col] = 1;

        f或 (i = 0; i < 4; i++) {
            int newRow = row + dy[i];
            int newCol = col + dx[i];

            if (isValidMove(matrix, newRow, newCol, visited)) {
                char *newPath = (char *)malloc((strlen(path) + 2) * sizeof(char));
                if (newPath == NULL) {
                    fprintf(stderr, "Mem或y allocation err或.\n");
                    exit(EXIT_FAILURE);
                }
                strcpy(newPath, path);

                if (i == 0) {
                    newPath[strlen(path)] = 'O';
                } else if (i == 1) {
                    newPath[strlen(path)] = 'E';
                } else if (i == 2) {
                    newPath[strlen(path)] = 'N';
                } else if (i == 3) {
                    newPath[strlen(path)] = 'S';
                }
                newPath[strlen(path) + 1] = '\0';

                newDistance = distance + 1;
                newBadCells = badCells + (matrix->matrix[newRow][newCol] == 0);
                newNegativeCells = negativeCells + (matrix->matrix[newRow][newCol] == -1);

                enqueue(queue, & queueSize, createBFSNode(newRow, newCol, newDistance, newBadCells, newNegativeCells, newPath));
                visited[newRow][newCol] = 1;
            }
        }

        if (path == check) {} else {
            free(path);
        }

    }

    f或 (i = 0; i < numRows; i++) {
        free(visited[i]);
    }
    free(visited);
    free(queue);
}

这个变量causes a mem或y leaknewPath,但它不是那么简单,让我解释一下

内存分配的工作原理如下: 队列以空/起始 node 开始,没有为该路径分配内存 然后,对于其后的每个 node ,每次在将该 node 入队之前,都会将一条路径分配为"newPath",然后在该 node 出队时将其释放为"path".

通过调试,我发现**free**()**malloc**()少1,所以最终无法释放一个内存块

所有其他内存都已正确分配和释放

我try 了许多不同的实现来解决这个问题,但都失败了

其中一些是:

 while (queueSize > 0) {
     qs或t(queue, queueSize, sizeof(BFSNode), pri或ityCompare);

     currentNode = dequeue(queue, & queueSize);
     row = currentNode.point.row;
     col = currentNode.point.col;
     distance = currentNode.distance;
     badCells = currentNode.badCells;
     negativeCells = currentNode.negativeCells;
     /* With a switch check if it's the first node 或 not then free path bef或e the new value is assigned */
     path = currentNode.path;

在While结束后再释放路径一次

EDIT个 希望凹痕现在已经修好了.

newPath is freed through path as they share the same mem或y allocation

Could any of you help me figure out a way to fix this issue? Thank you all f或 your time and help!

推荐答案

当您接受一个结果为(到目前为止的)最佳结果时,您可以执行以下操作(在两个控制路径中):

                free(bestResult->path);
                bestResult->path = strdup(path);

然后是continue到循环的下一次迭代.因此,您跳过释放当前 node 的path的代码,然后该 node 对象就会丢失.那是你的泄密.实际上,您可能会泄漏多个已分配的对象,具体取决于输入.

我假设您执行的是strdup(),而不是简单的赋值,因为当前 node 的路径有时可能是指向字符串的指针,使用最短路径结果的下游代码不能try 释放该字符串.但这迫使您对代码进行了几次扭曲.相反,为什么不从一开始就防止任何 node 包含这样的路径指针呢?

其他建议:

  • 不要依赖调用者提供的初始内容*bestResult,除非这是您想做的really.我倾向于认为不是,但很难说.

  • 避免通过指针数组模拟多维array.您不能在C90中使用可变长度数组,但您仍然可以在一维数组的基础上模拟2D数组,这可以更干净、更快.

  • 在尽可能窄的范围内声明变量.

  • 不要在同一条语句中声明多个变量.

  • 更喜欢在变量的声明中为其赋值 在可行的情况下

  • 不投malloc etc的结果.

  • Select calloc()胜于malloc()+memset胜于零.

  • 一般来说,根据要为其分配结果指针的变量来计算分配大小.这比在大小计算中对数据类型进行硬编码更具弹性,也更不容易出错.

  • 一般来说,不要说sizeof(char),因为这是1by definition.

  • 希望最大限度地减少代码重复.对于少量不必要的计算来说,这是一个合理的理由.

  • 考虑在获得Out参数的最终值之前不要写入该参数.这将在函数失败时保留调用方的原始值.

  • 当函数确实可以promise 不修改指向的对象时,可以考虑将指针参数声明为指向const个对象的指针.

  • 找到一种更好的方法来进行路径连接.

例如,

/* Function to find the shortest path in the matrix using BFS */
void findShortestPath(const Matrix *matrix, Result *bestResult) {
    static const int dx[] = { -1, 1, 0, 0 };
    static const int dy[] = { 0, 0, -1, 1 };
    static const char dir[][2] = { "O", "E", "N", "S" };

    int numRows = matrix->rows;
    int numCols = matrix->cols;

    // Note: this restructuring will require changes to isValidMove(), too:
    int *visited = calloc(numRows * numCols, sizeof(*visited));
    #define VISITED(r, c) (visited[(r) * numCols + (c)])

    BFSNode *queue = malloc(numRows * numCols * sizeof(*queue));
    int queueSize = 0;

    enqueue(queue, &queueSize, createBFSNode(0, 0, 0, 0, 0, strdup("")));

    // Reproduce the original code's dependence on the initial value
    // of *bestResult:
    Result workingBest = *bestResult;

    // Alternatively:
    // Result workingBest = { -1, 0, 0, NULL };  // check element order

    while (queueSize > 0) {
        qsort(queue, queueSize, sizeof(*queue), priorityCompare);

        BFSNode currentNode = dequeue(queue, &queueSize);
        int row = currentNode.point.row;
        int col = currentNode.point.col;
        // Check member order:
        Result result = {
           currentNode.distance,
           currentNode.badCells,
           currentNode.negativeCells,
           currentNode.path
        };

        if (row == numRows - 1 && col == numCols - 1) {
            if ((workingBest.distance == -1)
                    || (result.distance < workingBest.distance) 
                    || (result.distance == workingBest.distance
                            && result.negativeCells > workingBest.negativeCells)) {
                free(workingBest.path);
                workingBest = result;
            }

            continue;
        }

        VISITED(row, col) = 1;

        int i;
        for (i = 0; i < 4; i++) {
            int newRow = row + dy[i];
            int newCol = col + dx[i];

            if (isValidMove(matrix, newRow, newCol, visited)) {
                char *newPath = malloc(strlen(result.path) + 2);

                if (newPath == NULL) {
                    fprintf(stderr, "Memory allocation error.\n");
                    exit(EXIT_FAILURE);
                }
                sprintf(newPath, "%s%s", result.path, dir[i]);

                int newDistance = result.distance + 1;
                int newBadCells = result.badCells + (matrix->matrix[newRow][newCol] == 0);
                int newNegativeCells = result.negativeCells + (matrix->matrix[newRow][newCol] == -1);

                enqueue(queue, &queueSize, createBFSNode(
                            newRow, newCol, newDistance, newBadCells, newNegativeCells, newPath));
                VISITED(newRow, newCol) = 1;
            }
        }

        free(result.path);
    }

    free(visited);
    free(queue);

    *bestResult = workingBest;
    #undef VISITED
}

C++相关问答推荐

ISO_C_BINDING,从Fortran调用C

常数函数指针优化

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

如何解决C中的严格别名?

无法用C++编译我的单元测试

如何使用低级C++写出数值

如何使fputs功能提示错误输入并要求用户重新输入.程序停止而不是请求新的输入

我怎么才能用GCC编译一个c库,让它包含另一个库呢?

Flose()在Docker容器中抛出段错误

函数的限制限定指针参数允许优化调用方函数吗?

为什么我可以在GCC的标签后声明变量,但不能声明Clang?

如何在C中使数组变量的值为常量?

不同出处的指针可以相等吗?

当b是无符号字符时,int a=(b<;<;2)>;>;2;和int a=b&;0x3F;之间有什么区别?

如何使用FSeek和文件流指针在C中查找文件的前一个元素和前一个减go 一个元素

运行时错误:在索引数组时加载类型为';char';`的空指针

C中的回文数字

在运行时判断C/C++指针是否指向只读内存(在Linux操作系统中)

从文件到链表读取日期

%g浮点表示的最大字符串长度是多少?