使用递归函数时的C ++ Stack Overflow

时间:2014-04-01 13:39:18

标签: c++ recursion

我有一个具有递归功能的类。我测试了100个案例,代码工作正常。但是,我运行了另一个测试,并且在几次递归调用之后,收到了一个关于堆栈溢出的第一次机会异常,我选择忽略它,然后出现一个关于内存读取违规的未处理异常。

假设我有以下代码(不是真正的代码,它有退出条件):

class Foo {
    void Bar () {
        Bar();
    };
};

当我使用调试器时,我发现在调用Bar时,this指针收到错误的地址编号,导致Foo对象的读取错误而且我不知道不知道为什么。

有人知道吗?

或者我应该试试吗?

class Foo {
    static void Bar (Foo* obj) {
        Foo::Bar(obj);
    };
};

修改

以下是用于模拟游戏Jewel的真实代码。我在scanTile方法

中发现了问题
enum MOVE {MOVE_T, MOVE_L, MOVE_R, MOVE_B}; // Move Direction
enum SCORE {SCORE_3 = 1, SCORE_4 = 2, SCORE_5 = 4}; // Score Types
enum ERROR {ERR_DROP = 1, ERR_COUNT, ERR_MOVE}; // User-defined Error Code

class Jewel {
private:
    UINT32 m, n, score, x, y;
    char** map;
    bool** scanned;
    char move;

    void init () {
        map = new char*[n];
        scanned = new bool*[n];
        for (UINT32 i = 0; i < n; i++) {
            map[i] = new char[m];
            scanned[i] = new bool[n];
        };
    };

    void reinit () {
        for (UINT32 i = 0; i < n; i++)
            for (UINT32 j = 0; j < n; j++)
                scanned[i][j] = false;
    };

    void uninit () {
        for (UINT32 i = 0; i < n; i++) {
            delete[m] map[i];
            delete[n] scanned[i];
        };

        delete[n] map;
        delete[n] scanned;
    };

    void fileInput () {
        std::ifstream fInput("input.txt");
        fInput >> n >> m;

        init();

        for (UINT32 j = 0; j < m; j++)
            for (UINT32 i = 0; i < n; i++)
                fInput >> map[i][j];

        fInput.close();
    };

    void fileOutput () {
        std::ofstream fOutput("output.txt");
        fOutput << score << '\n';

        for (UINT32 j = 0; j < n; j++) {
            for (UINT32 i = 0; i < n; i++)
                fOutput << map[i][n - 1 - j] << ' ';
            fOutput << '\n';
        };

        fOutput.close();

        uninit();
    };

    bool inputMove () {
        std::cin >> x >> y >> move;
        if ((x == -1) && (y == -1) && (move == 'A'))
            return false;
        else
            return true;
    };

    void outputMove () {
        std::cout << '\n' << score << '\n';

        for (UINT32 j = 0; j < n; j++) {
            for (UINT32 i = 0; i < n; i++) {
                std::cout << map[i][n - 1 - j] << ' ';
            };

            std::cout << '\n';
        };
    };

    void swap(char &a, char &b) {
        char temp = a;
        a = b;
        b = temp;
    };

    bool beginMove () {
        switch (move) {
        case 'T':
            if (x < n - 1) {
                swap(map[y][x], map[y][x + 1]);
                return true;
            };
            break;
        case 'B':
            if (0 < x) {
                swap(map[y][x], map[y][x - 1]);
                return true;
            };
            break;
        case 'L':
            if (0 < y) {
                swap(map[y][x], map[y - 1][x]);
                return true;
            };
            break;
        case 'R':
            if (y < n - 1) {
                swap(map[y][x], map[y + 1][x]);
                return true;
            };
            break;
        };

        return false;
    };

    void revertMove () {
        switch (move) {
        case 'T':
            swap(map[y][x], map[y][x + 1]);
            break;
        case 'B':
            swap(map[y][x], map[y][x - 1]);
            break;
        case 'L':
            swap(map[y][x], map[y - 1][x]);
            break;
        case 'R':
            swap(map[y][x], map[y + 1][x]);
            break;
        };
    };

    void drop () {
        for (UINT32 i = 0; i < n; i++) {
            UINT32 j = 0;

            while (j < n && map[i][j])
                j++;

            if (j < n) {
                UINT32 k = j + 1;

                while (j < n)
                    if (!map[i][j]) {
                        while ((k < m) && !map[i][k])
                            k++;

                        if (!map[i][k])
                            exit(ERR_DROP);

                        map[i][j] = map[i][k];
                        map[i][k] = 0;

                        j++;
                        k++;
                    };
            };
        };
    };

    bool scanMap () {
        reinit();
        UINT32 sessionScore = 0;

        for (UINT32 j = 0; j < n; j++)
            for (UINT32 i = 0; i < n; i++)
                if (!scanned[i][j])
                    sessionScore += startScan(i, j);

        if (sessionScore) {
            score += sessionScore;
            return true;
        } else
            return false;
    };

    UINT32 startScan(const UINT32 &col, const UINT32 &row) {
        UINT32 count = 1;
        scanned[col][row] = true;

        if ((row < n - 1) && !scanned[col][row + 1] && (map[col][row] == map[col][row + 1]))
            count += scanTile(col, row + 1, MOVE_T, (0 < row) && (map[col][row] == map[col][row - 1]));

        if ((0 < row) && !scanned[col][row - 1] && (map[col][row] == map[col][row - 1]))
            count += scanTile(col, row - 1, MOVE_B, (row < n - 1) && (map[col][row] == map[col][row + 1]));

        if ((col < n - 1) && !scanned[col + 1][row] && (map[col][row] == map[col + 1][row]))
            count += scanTile(col + 1, row, MOVE_R, (0 < col) && (map[col][row] == map[col - 1][row]));

        if ((0 < col) && !scanned[col - 1][row] && (map[col][row] == map[col - 1][row]))
            count += scanTile(col - 1, row, MOVE_L, (col < n - 1) && (map[col][row] == map[col + 1][row]));

        if ((count < 3) && (count != 1))
            exit(ERR_COUNT);

        if (count >= 3)
            map[col][row] = 0;

        if (count == 1)
            return 0;
        else if (count == 3)
            return count*SCORE_3;
        else if (count == 4)
            return count*SCORE_4;
        else if (count >= 5)
            return count*SCORE_5;
    };

    UINT32 scanTile(const UINT32 &col, const UINT32 &row, const MOVE &direction, const bool &opposite = false) {
        UINT32 count = 1;
        UINT32 temp = 0;
        bool counted = false;

        switch (direction) {
        case MOVE_T:
            if ((row < n - 1) && (map[col][row] == map[col][row + 1]))
                if (scanned[col][row + 1])
                    counted = true;
                else
                    count += scanTile(col, row + 1, MOVE_T, (0 < row) && (map[col][row] == map[col][row - 1]));
            break;
        case MOVE_B:
            if ((0 < row) && (map[col][row] == map[col][row - 1]))
                if (scanned[col][row - 1])
                    counted = true;
                else
                    count += scanTile(col, row - 1, MOVE_B, (row < n - 1) && (map[col][row] == map[col][row + 1]));
            break;
        case MOVE_R:
            if ((col < n - 1) && (map[col][row] == map[col + 1][row]))
                if (scanned[col + 1][row])
                    counted = true;
                else
                    count += scanTile(col + 1, row, MOVE_R, (0 < col) && (map[col][row] == map[col - 1][row]));
            break;
        case MOVE_L:
            if ((0 < col) && (map[col][row] == map[col - 1][row]))
                if (scanned[col - 1][row])
                    counted = true;
                else
                    count += scanTile(col - 1, row, MOVE_L, (col < n - 1) && (map[col][row] == map[col + 1][row]));
            break;
        default:
            exit(ERR_MOVE);
        };

        if ((opposite ? 1 : 0) + 1 + count + (counted ? 1 : 0) >= 3) {
            switch (direction) {
            case MOVE_T:
            case MOVE_B:
                temp = 0;
                if ((col < n - 1) && !scanned[col + 1][row] && (map[col][row] == map[col + 1][row]))
                    count += temp = scanTile(col + 1, row, MOVE_R, (0 < col) && (map[col][row] == map[col - 1][row]));
                if ((0 < col) && !scanned[col - 1][row] && (map[col][row] == map[col - 1][row]))
                    count += scanTile(col - 1, row, MOVE_L, temp ? true : false);
                break;
            case MOVE_L:
            case MOVE_R:
                temp = 0;
                if ((row < n - 1) && !scanned[col][row + 1] && (map[col][row] == map[col][row + 1]))
                    count += temp = scanTile(col, row + 1, MOVE_T, (0 < row) && (map[col][row] == map[col][row - 1]));
                if ((0 < row) && !scanned[col][row - 1] && (map[col][row] == map[col][row - 1]))
                    count += scanTile(col, row - 1, MOVE_B, temp ? true : false);
                break;
            default:
                exit(ERR_MOVE);
            };

            scanned[col][row] = true;
            map[col][row] = 0;
            return count;
        } else {
            return 0;
        };
    };

public:
    Jewel () : score(0) {
        fileInput();
    };

    void process () {
        outputMove();

        while (inputMove()) {
            if (beginMove()) {
                bool first = true;

                while (scanMap()) {
                    outputMove();
                    drop();
                    outputMove();
                    first = false;
                };

                if (first)
                    revertMove();
            };

            outputMove();
        };

        fileOutput();
    };
};

2 个答案:

答案 0 :(得分:1)

使用递归时,必须始终具有退出条件。

堆栈溢出通常发生在没有堆栈溢出时,或者当它太远意味着你的递归太深时。

答案 1 :(得分:1)

堆栈,和其他许多东西一样,是一个有限大小的东西,你的递归使用的是越来越多的空间,直到你用完为止你的程序溢出。

在基于* nix的操作系统下,通常可以使用命令ulimit -aulimit -s(更短的输出)来获取堆栈的大小,这在GNU / linux发行版下通常约为7 / 8Mb