传递多维数组时出错,求原因及解决方法(附N皇后回溯代码)
多维数组传递错误的成因与解决办法
兄弟,我一眼就看穿你代码里的问题了——就是二维数组作为函数参数传递时踩的C++语法坑!咱们先把问题掰碎了说:
错误成因
C对多维数组的类型要求很严格:当你把二维数组传给函数时,除了第一维可以留空,其他所有维度必须是编译期就能确定的常量。你代码里的s是函数参数,属于运行时才会确定的值,编译器在编译阶段根本不知道s到底是多少,自然没法计算数组元素在内存里的偏移地址(毕竟二维数组在内存里是连续存储的,得靠固定的第二维大小来定位元素)。所以int arr[][s]这种写法直接违反了C的语法规则,编译器肯定会报错。
解决办法
给你几个实用的方案,按需选择:
方案1:用编译期常量定义数组大小
如果你的N皇后问题里的棋盘大小是固定的(比如8皇后),直接把s改成编译期常量就行:
#include <iostream> using namespace std; // 用constexpr或者#define定义常量 constexpr int s = 8; bool attack_checking(int arr[][s], int i, int j) { // 检查行 for(int x = 0; x < s; x++) if(arr[i][x] == 1) return true; // 检查列 for(int x = 0; x < s; x++) if(arr[x][j] == 1) return true; // 检查对角线(补全你没写完的逻辑) for(int x = i, y = j; x >=0 && y >=0; x--, y--) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y < s; x++, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x >=0 && y < s; x--, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y >=0; x++, y--) if(arr[x][y] == 1) return true; return false; } int main() { int board[s][s] = {0}; // 后续逻辑... return 0; }
缺点:棋盘大小固定,没法动态调整。
方案2:改用std::vector<std::vector<int>>(最推荐)
C++的容器能完美解决动态数组的问题,而且不需要操心内存管理,代码更安全灵活:
#include <iostream> #include <vector> using namespace std; bool attack_checking(const vector<vector<int>>& arr, int i, int j) { int s = arr.size(); // 检查行 for(int x = 0; x < s; x++) if(arr[i][x] == 1) return true; // 检查列 for(int x = 0; x < s; x++) if(arr[x][j] == 1) return true; // 检查对角线 for(int x = i, y = j; x >=0 && y >=0; x--, y--) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y < s; x++, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x >=0 && y < s; x--, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y >=0; x++, y--) if(arr[x][y] == 1) return true; return false; } int main() { int s = 8; // 这里可以动态输入s的值 vector<vector<int>> board(s, vector<int>(s, 0)); // 后续逻辑... return 0; }
优点:支持动态调整棋盘大小,代码可读性高,还能避免数组越界的风险。
方案3:使用指针的指针(int**)
如果你坚持要用原生数组,可以用动态分配的指针数组,但要注意手动管理内存:
#include <iostream> #include <cstdlib> using namespace std; bool attack_checking(int** arr, int s, int i, int j) { // 检查行 for(int x = 0; x < s; x++) if(arr[i][x] == 1) return true; // 检查列 for(int x = 0; x < s; x++) if(arr[x][j] == 1) return true; // 检查对角线 for(int x = i, y = j; x >=0 && y >=0; x--, y--) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y < s; x++, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x >=0 && y < s; x--, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y >=0; x++, y--) if(arr[x][y] == 1) return true; return false; } int main() { int s = 8; // 动态分配指针数组 int** board = (int**)malloc(s * sizeof(int*)); for(int i = 0; i < s; i++) { board[i] = (int*)malloc(s * sizeof(int)); // 初始化数组为0 for(int j = 0; j < s; j++) board[i][j] = 0; } // 后续逻辑... // 记得释放内存 for(int i = 0; i < s; i++) free(board[i]); free(board); return 0; }
缺点:需要手动分配和释放内存,容易出现内存泄漏或野指针问题,不推荐新手使用。
方案4:模板函数(适配编译期常量大小)
如果你想保留原生数组的性能,同时支持不同的固定大小,可以用模板函数:
#include <iostream> using namespace std; template<int s> bool attack_checking(int arr[][s], int i, int j) { // 检查行 for(int x = 0; x < s; x++) if(arr[i][x] == 1) return true; // 检查列 for(int x = 0; x < s; x++) if(arr[x][j] == 1) return true; // 检查对角线 for(int x = i, y = j; x >=0 && y >=0; x--, y--) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y < s; x++, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x >=0 && y < s; x--, y++) if(arr[x][y] == 1) return true; for(int x = i, y = j; x < s && y >=0; x++, y--) if(arr[x][y] == 1) return true; return false; } int main() { const int s = 8; int board[s][s] = {0}; // 调用时编译器会自动推导模板参数s bool isAttacked = attack_checking(board, 2, 3); // 后续逻辑... return 0; }
优点:保留原生数组的性能,支持不同的固定大小;缺点:还是没法动态调整大小,s必须是编译期常量。
内容的提问来源于stack exchange,提问作者Vivek
相关产品推荐
相关产品推荐

