【问题标题】:Segmentation Fault - Array out of bounds分段错误 - 数组越界
【发布时间】:2017-09-28 10:37:52
【问题描述】:

我编写了一个简单的算法,这样当用户输入一个 int N 时,它会创建一个 N×N 网格,其中在同一行或同一列中没有重复项。该算法有时适用于较小的数字,但通常会引发分段错误。错误发生在设置网格数组元素的行中的 noRowDuplicates 函数中。

我不确定为什么会发生这种情况,希望能提供任何帮助。提前致谢!

// Author: Eric Benjamin
// This problem was solved using recursion. fill() is the recursive function.


#include <iostream>
#include <cstdlib>
#include <time.h>

using namespace std;

void fillOptions();
void fill(int arrayPosition);
int inputNum;
int gridSize;
int *grid;
int allOptionsSize = 0;
int *allOptions;

int main() {
    cout << "Please enter a number!" << endl;
    cin >> inputNum;
    gridSize = inputNum * inputNum;

    grid = new int[gridSize];
    allOptions = new int[inputNum];
    for (int i = 0; i < inputNum; i++) {
         allOptions[i] = i + 1;
         allOptionsSize++;
    }

    srand((unsigned)time(0));
    fill(0);

    delete[] grid;
    delete[] allOptions;
    return 0;
}

bool noColumnDuplicates(int arrPosition, int valueToCheck) {
    for (int i = 1; i < inputNum; i++) {
        if (arrPosition - (inputNum * i) >= 0) {
            if (grid[arrPosition - (inputNum * i)] == valueToCheck) {
                return false;
            }
        }
    }
    return true;
}

bool noRowDuplicates(int arrPosition, int valueToCheck) {
    int rowPosition = arrPosition % inputNum; // 0 to num - 1
    if (rowPosition > 0) {
        for (int p = 1; p < rowPosition + 1; p++) {
            if (grid[arrPosition - p] == valueToCheck) {
                return false;
            }
        }
    }
    return true;
}

void fill(int arrayPosition) {
    if (arrayPosition < gridSize) {
        int randomPosition = rand() % allOptionsSize;
        grid[arrayPosition] = allOptions[randomPosition];
        if (noColumnDuplicates(arrayPosition, grid[arrayPosition])) {
            if (noRowDuplicates(arrayPosition, grid[arrayPosition])) {
                if (arrayPosition % inputNum == 0) {
                    cout << endl;
                }
                cout << grid[arrayPosition] << " ";
                fill(arrayPosition + 1);
            } else {
                fill (arrayPosition);
            }
        } else {
            fill(arrayPosition);
        }
    }
}

【问题讨论】:

  • 提示:在 C++ 中停止使用 C 风格的数组,而改用 std::vector
  • 警告:使用rand() is considered harmful,强烈建议您使用适当的random number generator facility in the Standard Library,它会产生实际随机值。您使用time(NULL) 作为随机数种子意味着如果在同一秒内运行,这将产生相同的结果,并且在许多平台上rand()barely random at all
  • 是时候学习如何调试代码了
  • 去掉所有的全局变量。
  • 不清楚fill 做了什么,你没有显示代码,但我敢打赌你的问题出在某个地方。

标签: c++ arrays recursion


【解决方案1】:

您对 fill() 的初始调用将为其参数传递 0,arrayPosition

gridSize 是矩阵/数组的大小。

如果您检查fill() 中的逻辑,您将得出结论,除非arrayPosition 等于或大于gridSize,否则将递归调用fill()arrayPosition 要么是相同,或增加 1。

通过fill() 的所有逻辑执行路径,当arrayPosition &lt; gridSize 时,会导致对fill() 的递归调用。

换句话说,例如,如果您的数组/矩阵有一万个值,您的 fill() 将尝试对其自身进行至少(并且可能更多)一万次嵌套递归调用!

这不会有好的结局。当您的代码超出您的操作系统分配给它的最大堆栈空间量时,您的代码会遇到分段错误,并且您的操作系统拒绝为您的进程分配更多的堆栈空间。

您需要重构您的逻辑,以避免这种失控的递归。不幸的是,堆栈空间不是无限的。显示的逻辑在 C++ 中根本被破坏。您不能依赖编译器消除尾递归,并避免每次递归函数调用都消耗堆栈空间。

一个简短的评论表明嵌套递归可以简单地替换为while 循环。整体算法还有一些改进的空间,但至少这会解决递归问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多