我有一个具有递归功能的类。我测试了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();
};
};
答案 0 :(得分:1)
使用递归时,必须始终具有退出条件。
堆栈溢出通常发生在没有堆栈溢出时,或者当它太远意味着你的递归太深时。
答案 1 :(得分:1)
堆栈,和其他许多东西一样,是一个有限大小的东西,你的递归使用的是越来越多的空间,直到你用完为止你的程序溢出。
在基于* nix的操作系统下,通常可以使用命令ulimit -a
或ulimit -s
(更短的输出)来获取堆栈的大小,这在GNU / linux发行版下通常约为7 / 8Mb