我用C语言创建了一个函数,用递归的方法找到走出三角形迷宫的最短路径.我在函数中使用了两个全局变量,我想go 掉它们,因为我知道全局变量不应该被使用.

变量moves,我可以作为参数传递,但我不知道这样使堆栈不堪重负是不是糟糕的内存管理. 另一个全局变量foundExit不能作为参数使用,所以我不知道如何go 掉它.

So my question is whether I should use global variables in case of recursion.

请注意,我们数组中的每个数字都是某个3位数字,其中1表示墙,0表示空墙.001是左墙,010是右墙,100是下墙/上墙.例如,111代表有他所有墙壁的三角形.

保存在单元格中的迷宫图片:

image of our maze

简化代码:

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

typedef struct {
    int rows;
    int cols;
    unsigned char *cells;
} Map;

void NegateEntraceBit(Map *map, unsigned char r, unsigned char c) {
    char whichWall;
    if (c == 0) { // From left.
        whichWall = 0;
    }
    else if (c == map->cols - 1) { // From right.
        whichWall = 1;
    }
    else if (r == 0) { // From up.
        whichWall = 2;
    }
    else if (r == map->rows - 1) { // From down.
        whichWall = 2;
    }

    //Inverting entrace bit.
    map->cells[map->cols * r + c] ^= (1 << whichWall); 
}

char InvertDirection(char direction) {
    if (direction == 0) {
        return 1;
    }
    else if (direction == 1) {
        return 0;
    } else {
        return 2;
    }
}

char moves[2][3][2] = {
    {{0,-1}, {0,1}, {-1,0}},
    {{0,-1}, {0,1}, {1,0}}
};

bool foundExit = false;

void shortestPath(Map map, int r, int c, char direction) {
/* 
         (r+c) % 2 == 1:        (r+c) % 2 == 0:
                ^               _________
              ╱   ╲             ╲   2   ╱
           0 ╱     ╲ 1         0 ╲     ╱ 1
            ╱_______╲             ╲   ╱
                2                   v
*/
    
    // Going in the direction if its the only way (triangle has value 0b100).
    while (map.cells[map.cols * r + c] == 3) {
        r += moves[(r+c) & 1][direction][0];
        c += moves[(r+c) & 1][direction][1];

        // This validating is performed when we go in 1 line to the exit.
        if (r < 0 || r >= map.rows || c < 0 || c >= map.cols) { // Outside position
            foundExit = true;
            return;
        }
    }

    // This validating is performed when a new instance is called.
    if (r < 0 || r >= map.rows || c < 0 || c >= map.cols) { // Outside position
        foundExit = true;
        return;
    }

    // This validating is performed when the only other way is in inverted direction.
    if ((map.cells[map.cols * r + c] ^ (1 << InvertDirection(direction))) == 0b111) {
        return;
    }

    printf("%d,%d\n", r+1, c+1);

    // For any other direction
    for (char direc = 0; direc < 3; direc++) {
        // that is (available && not in inverted direction),
        if ( !(map.cells[map.cols * r + c] & (1 << direc)) && (direc != InvertDirection(direction))) {
            // we call new instance with new coordinates.
            shortestPath(map,
                         r + moves[(r+c) & 1][direc][0], 
                         c + moves[(r+c) & 1][direc][1], 
                         direc);
        } 
        // Stopping any other instance that would be called even when the exit is found.
        if (foundExit) {
            break;
        }            
    }
}

int main() {
    Map map;
    map.rows = 6;
    map.cols = 7; // Set to the number of columns in your data

    // Allocate memory for 1D array
    map.cells = malloc(sizeof(unsigned char) * (map.rows * map.cols));

    // Initialize the 1D array directly
    unsigned char initialData[] = {
        1, 4, 4, 2, 5, 0, 6,
        1, 4, 4, 0, 4, 0, 2,
        1, 0, 4, 0, 4, 6, 1,
        1, 2, 7, 1, 0, 4, 2,
        3, 1, 4, 2, 3, 1, 2,
        4, 2, 5, 0, 4, 2, 5
    };

    for (int i = 0; i < map.rows * map.cols; i++) {
        map.cells[i] = initialData[i];
    }
    int r = 6;
    int c = 1;

    int rows = r-1;
    int cols = c-1;

    // Closing entrace bit so its not the shortest path out.
    NegateEntraceBit(&map, rows, cols);
    //For every direction
    for (char direc = 0; direc < 3; direc++) {
        // That is available (0).
        if ( !(map.cells[map.cols * rows + cols] & (1 << direc)) ) {
            shortestPath(map, rows, cols, direc);
        }     
    }

    // Free allocated memory
    free(map.cells);

    return 0;
}

推荐答案

这两个全局变量在单个函数shortestPath()中被访问,因此它们可以在该函数内被声明为static.

void shortestPath(Map map, int r, int c, char direction) 
{
    static char moves[2][3][2] = {
        {{0,-1}, {0,1}, {-1,0}},
        {{0,-1}, {0,1}, {1,0}}
    };

    static bool foundExit = false;

    ...

在多个函数之间共享变量的其他情况下,将所有这些函数和变量放在单独编译的源文件中,并声明变量和任何未被外部引用的函数(在本例中是linkage specifier而不是上面的storage class specifier),并将作用域限制到该转换单元(因此不再是全局的).

请注意,如果是全局变量,这是该问题的一般解决方案.它并不是专门针对递归的,递归通常也是不明智的.还有其他一些技术.可以编写任何大小的代码,而根本不需要全局变量.

C++相关问答推荐

如何将不同长度的位转换成字节数组?

将常量转换为指针会增加.数据大小增加1000字节

N的值设置为0或1(未定义的行为),而我正在try 学习realloc和Malloc的用法

在基本OpenGL纹理四边形中的一个三角形中进行渲染

X64:并发写入布尔数组

为什么我的Hello World EFI程序构建不正确?

使用TCL C API导航到列表中的元素

为什么这个分配做得不好呢?

C";中的ANN运行时判断失败#2-变量outputLayer;周围的堆栈已损坏.运行后出错

使用Open62541向OPCUA服务器发送读请求时内存泄漏

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

赋值两侧的后置增量,字符指针

如何在MSVC中使用intSafe.h函数?

挥发性语义的形式化理解

C: NULL>;NULL总是false?

如何找出C中分配在堆上的数组的大小?

C/C++编译器可以在编译过程中通过按引用传递来优化按值传递吗?

cs50拼写器分配中的无限循环

C11 嵌套泛型

返回指向函数内声明的复合文字的指针是否安全,还是应该使用 malloc?