对 char 数组的操作如何导致堆栈溢出?
How does manipulation of a char array cause a stack overflow?
如果有明显的缺陷,我很抱歉。我对内存还很陌生,所以我对堆栈溢出的工作原理有一些了解,据我所知,我所做的任何事情都不会导致堆栈溢出。我所做的只是更改字符串中的字符。
我知道数组是指针,但更改值会导致堆栈溢出吗?
相关函数如下:
char base[] = "aaaaa";
void changeLetters(int position) { // Stack overflow happens around here
if (base[position] != 'z') {
base[position]++;
}
// When I include a cout here, I also get a stack overflow
if (position == 4 && base[position] != 'z') {
changeLetters(position);
}
else if (base[position] == 'z' && position != 0) {
base[position] = 'a';
changeLetters(position - 1);
}
else if (position < 4) {
changeLetters(position + 1);
}
}
当没有 std::cout
时,我得到
Unhandled exception at 0x767C3210 (KernelBase.dll) in passwordCracker.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x01002FFC).
否则
Unhandled exception at 0x009C38B9 in passwordCracker.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x006D2F8C).
编辑:
该函数在主循环中调用。传递的值是字符串 (4) 的长度,它会一直运行下去。我没有提到的一件奇怪的事情是,如果我循环使用较少数量的字母(a、b、c、d),它会完美地工作,但如果我让它循环遍历字母表,我只会收到堆栈溢出。
您的代码正在遍历由字母 a-z
组成的所有长度为 5
的字符串。这本身不是问题,但是您必须确保最大调用深度不会太大。
在 changeLetters
的每次迭代中,您最多增加一个字母一次,然后再次调用 changeLetters
,您最多进行一次这样的调用。
因此,您的调用图是完全线性的,对于每个 26^5
字符串,您都在进行另一个深度递归调用,因此最后的调用堆栈将有那么大。问题是,这是一个非常大的数字 26^5 = 11881376
,可能很容易大于您可能使用的堆栈 space。
您需要将线性调用图变成一个带有分支的调用图,例如在当前字符的位置上使用循环而不是每次调用 changeLetters
。
递归不是无限的,但它很深。深度足以炸毁堆栈。
函数每次递增一个字母时都使用递归。因为有 5 个字符,每个字符有 26 个可能的值,所以递归是 265 = 11881376 层深。我不确定您的堆栈有多大,但它不足以处理那么多级别。所以你得到一个堆栈溢出。
切换到使用嵌套循环的迭代解决方案。
如果有明显的缺陷,我很抱歉。我对内存还很陌生,所以我对堆栈溢出的工作原理有一些了解,据我所知,我所做的任何事情都不会导致堆栈溢出。我所做的只是更改字符串中的字符。
我知道数组是指针,但更改值会导致堆栈溢出吗?
相关函数如下:
char base[] = "aaaaa";
void changeLetters(int position) { // Stack overflow happens around here
if (base[position] != 'z') {
base[position]++;
}
// When I include a cout here, I also get a stack overflow
if (position == 4 && base[position] != 'z') {
changeLetters(position);
}
else if (base[position] == 'z' && position != 0) {
base[position] = 'a';
changeLetters(position - 1);
}
else if (position < 4) {
changeLetters(position + 1);
}
}
当没有 std::cout
时,我得到
Unhandled exception at 0x767C3210 (KernelBase.dll) in passwordCracker.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x01002FFC).
否则
Unhandled exception at 0x009C38B9 in passwordCracker.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x006D2F8C).
编辑: 该函数在主循环中调用。传递的值是字符串 (4) 的长度,它会一直运行下去。我没有提到的一件奇怪的事情是,如果我循环使用较少数量的字母(a、b、c、d),它会完美地工作,但如果我让它循环遍历字母表,我只会收到堆栈溢出。
您的代码正在遍历由字母 a-z
组成的所有长度为 5
的字符串。这本身不是问题,但是您必须确保最大调用深度不会太大。
在 changeLetters
的每次迭代中,您最多增加一个字母一次,然后再次调用 changeLetters
,您最多进行一次这样的调用。
因此,您的调用图是完全线性的,对于每个 26^5
字符串,您都在进行另一个深度递归调用,因此最后的调用堆栈将有那么大。问题是,这是一个非常大的数字 26^5 = 11881376
,可能很容易大于您可能使用的堆栈 space。
您需要将线性调用图变成一个带有分支的调用图,例如在当前字符的位置上使用循环而不是每次调用 changeLetters
。
递归不是无限的,但它很深。深度足以炸毁堆栈。
函数每次递增一个字母时都使用递归。因为有 5 个字符,每个字符有 26 个可能的值,所以递归是 265 = 11881376 层深。我不确定您的堆栈有多大,但它不足以处理那么多级别。所以你得到一个堆栈溢出。
切换到使用嵌套循环的迭代解决方案。