基于栈的N皇后问题C语言实现:段错误(核心已转储)排查求助
首先咱们先定位你遇到的**段错误(segmentation fault)**的直接原因,再梳理代码里的其他逻辑问题,最后给出修正后的完整代码。
导致段错误的核心问题
你在isValid函数里的这段代码是罪魁祸首:
for (int i = sizeof(colStore)-1; i>=0; i--) { push(ptt,colStore[i]); }
sizeof(colStore)返回的是数组的总字节数,而非数组的元素个数。比如如果colStore是包含3个int的数组(假设int占4字节),sizeof(colStore)会返回12,这时候i从11开始循环,访问colStore[11]完全是越界操作——这会破坏栈的内部数据,导致后续row或者colStore[i]变成非法值,最终在arr[row][colStore[i]]这行触发段错误。
正确的做法是用栈的大小(也就是Size变量)来作为数组的元素个数,循环应该改成:
for (int i = Size-1; i >= 0; i--) { push(ptt, colStore[i]); }
代码里的其他逻辑错误
除了段错误,你的代码还有几个会导致功能失效的问题:
isValid函数里错误重置currentPosition
你在函数开头写了currentPosition=0;,这会把传入的当前列位置直接覆盖成0,导致永远只判断第0列是否合法,完全不符合逻辑,必须删掉这行。print函数里的newStruct拼写错误
你调用了newStruct(n),但你的栈创建函数是newStack,这里应该改成newStack(n),否则会因为未定义函数导致编译错误。isValid函数中不必要的二维数组arr
其实不需要创建整个二维数组来判断斜线冲突,我们可以直接通过栈里存储的列位置和当前位置计算斜线关系,这样能简化代码,避免数组越界风险。
修正后的完整代码
#include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <math.h> struct stack { int maxsize; int top; int *items; }; struct stack* newStack(int capacity) { struct stack *pt = (struct stack*)malloc(sizeof(struct stack)); pt->maxsize = capacity; pt->top = -1; pt->items = (int*)malloc(sizeof(int) * capacity); return pt; } int size(struct stack *pt) { return pt->top + 1; } int isEmpty(struct stack *pt) { return pt->top == -1; } int isFull(struct stack *pt) { return pt->top == pt->maxsize - 1; } void push(struct stack *pt, int x) { if (isFull(pt)) { printf("\nOverflow"); exit(EXIT_FAILURE); } pt->items[++pt->top] = x; } int peek(struct stack *pt) { if (!isEmpty(pt)) { return pt->items[pt->top]; } else { exit(EXIT_FAILURE); } } int pop(struct stack *pt) { if (isEmpty(pt)) { printf("\nUnderflow"); exit(EXIT_FAILURE); } return pt->items[pt->top--]; } void print(struct stack *s, int n) { int Size = size(s); struct stack *temp = newStack(n); // 先把栈元素弹出到临时栈,同时打印 for (int i = 0; i < Size; i++) { int col = pop(s); push(temp, col); for (int j = 0; j < n; j++) { if (j == col) { printf("Q "); } else { printf("* "); } } printf("\n"); } // 把元素放回原栈 while (!isEmpty(temp)) { push(s, pop(temp)); } printf("\n"); } bool isValid(struct stack *ptt, int currentPosition, int n) { if (isEmpty(ptt)) { return true; } int Size = size(ptt); int colStore[Size]; bool isvalid = true; // 弹出栈元素,检查列冲突,同时保存列位置 for (int i = 0; i < Size; i++) { int col = pop(ptt); colStore[i] = col; if (col == currentPosition) { isvalid = false; } } // 把元素放回栈 for (int i = Size - 1; i >= 0; i--) { push(ptt, colStore[i]); } if (!isvalid) { return false; } // 检查斜线冲突:当前位置是第 (n - Size - 1) 行,currentPosition 列 int currentRow = n - Size - 1; for (int i = 0; i < Size; i++) { int existingRow = n - Size + i; int existingCol = colStore[i]; // 斜线判断:行差的绝对值等于列差的绝对值 if (abs(currentRow - existingRow) == abs(currentPosition - existingCol)) { return false; } } return true; } int solve(struct stack *p, int n) { int currentPosition = 0; int counter = 0; while (true) { bool isvalid = false; while (currentPosition < n) { if (isValid(p, currentPosition, n)) { push(p, currentPosition); currentPosition = 0; isvalid = true; break; // 找到合法列后,跳出循环处理下一行 } else { currentPosition++; } } if (!isvalid) { if (isEmpty(p)) { printf("\nEnd"); break; } else { currentPosition = pop(p); currentPosition++; } } if (size(p) == n) { print(p, n); currentPosition = pop(p); currentPosition++; counter++; } } if (counter > 0) { printf("\nNumber of solutions found: %d", counter); } else { printf("\nNo solution found"); } return counter; } int main() { int n; printf("\nEnter n: "); scanf("%d", &n); struct stack *pt = newStack(n); solve(pt, n); // 释放内存,避免内存泄漏 free(pt->items); free(pt); return 0; }
关键修改说明
- 修复了
sizeof(colStore)的错误,改用Size(栈的元素个数)来循环恢复栈元素。 - 删除了
isValid函数中错误的currentPosition=0;赋值,保证判断的是传入的当前列。 - 替换了
print函数里的newStruct为newStack。 - 简化了斜线冲突的判断逻辑,不需要创建二维数组,直接通过行号和列号的差值绝对值判断是否在同一条斜线上。
- 在
main函数中添加了内存释放代码,避免内存泄漏。 - 在
solve函数的合法列判断循环中添加了break,找到合法列后直接处理下一行,避免不必要的循环。
现在你可以编译运行这段代码,输入n的值(比如4),就能看到正确的N皇后解决方案了。
内容的提问来源于stack exchange,提问作者user16959642

