【发布时间】:2018-06-19 19:18:13
【问题描述】:
我必须为解决数独难题的作业创建一个程序。用户需要输入包含数字的二进制文件的名称(不是真正的二进制文件,它只是扩展名为 .bin,也可以用记事本、notepad++ 等打开)。这些数字代表拼图上的坐标以及这些坐标中包含的数字,例如 432 表示第 4 行第 3 列包含数字 2。填写拼图后,我需要解决它并将其打印在屏幕上。执行程序后它崩溃了,所以我决定使用一些开发人员认为最好的 MSVC 2017 调试器来查找和修复错误。这是我的代码:
数独.c
#include <stdio.h>
#include <stdlib.h>
#include "stdafx.h"
#include "sudokulib.h"
#define MALLOC_ERROR 0xFF
#define FILE_NOT_FOUND 0xFFF
#define ROWS 9
#define COLUMNS 9
int main(int argc, char ** argv)
{
char **matrix;
int i, args;
int row, column, num;
FILE * fp;
char * filename;
char * importedData;
matrix = (char **)malloc(ROWS * sizeof(char *));
if (!matrix)
exit(MALLOC_ERROR);
for (i = 0; i<ROWS; ++i)
{
matrix[i] = (char *)malloc(COLUMNS * sizeof(char));
if (!matrix[i])
exit(MALLOC_ERROR);
}
initSudoku(matrix);
printf ("Give me the name of data file: ");
filename = (char *)malloc(100 * sizeof(char));
if (!filename)
exit(MALLOC_ERROR);
scanf("%99s", filename);
fp = fopen(filename, "rb");
if (!fp)
{
printf ("File not found\n");
exit(FILE_NOT_FOUND);
}
importedData = (char *)malloc(sizeof(char)*ROWS*COLUMNS * 3);
if (!importedData)
exit (MALLOC_ERROR);
args = fread(importedData, 1, 243, fp);
i = 0;
while (importedData[i] != ' ' && importedData[i + 1] != ' ' && importedData[i + 2] != ' ' && importedData[i] >= '1' && importedData[i + 1] >= '1' && importedData[i + 2] >= '1' && importedData[i] <= '9' && importedData[i + 1] <= '9' && importedData[i + 2] <= '9' && i < 243)
{
row = importedData[i] - '0' - 1; /* Convert from ascii code to number */
column = importedData[i + 1] - '0' - 1;
num = importedData[i + 2] - '0';
matrix[row][column] = num;
i = i + 3;
}
printf("Sudoku after importing data:\n\n");
printSudoku(matrix);
system("pause");
if (solvePuzzle(matrix))
{
printSudoku(matrix);
}
else
printf ("Puzzle has no solution\n");
fclose(fp);
free(filename);
for (i = 0; i<9; ++i)
{
free(matrix[i]);
}
free(matrix);
return 0;
}
数独库.h
#pragma once
#include <stdlib.h>
#include <stdio.h>
/* Function Prototypes Begin Here */
void printSudoku(char **);
void initSudoku(char **);
int checkRow(char **, int, int);
int checkCol(char **, int, int);
int check3x3(char **, int, int, int);
int checkIfEmpty(char **, int*, int*);
int solvePuzzle (char **);
/* Function Prototypes End Here */
void printSudoku(char ** Mat)
{
int i, j;
for (i = 0; i<9; ++i)
{
printf ("-------------------\n");
printf("|");
for (j = 0; j<9; ++j)
{
printf("%d|", Mat[i][j]);
}
printf("\n");
}
printf ("-------------------\n");
}
void initSudoku(char ** Mat)
{
int i, j;
for (i = 0; i<9; ++i)
for (j = 0; j<9; ++j)
Mat[i][j] = 0;
}
int checkRow (char ** Mat, int row, int num) // if row is free returns 1 else returns 0
{
int col;
for (col = 0; col < 9; col++)
{
if (Mat[row][col] == num)
{
return 0;
}
}
return 1;
}
int checkCol (char ** Mat, int col, int num) // if column is free returns 1 else returns 0
{
int row;
for (row = 0; row < 9; row++)
{
if (Mat[row][col] == num)
{
return 0;
}
}
return 1;
}
int check3x3 (char ** Mat, int row, int col, int num) // if number doesnt exist in the 3x3 grid returns 1 else returns 0
{
row = (row / 3) * 3; // set to first row in the grid
col = (col / 3) * 3; // set to first col in the grid
int i;
int j;
for (i = 0; i < 3; i++) // grid is 3x3
{
for (j = 0; j < 3; j++)
{
if (Mat[row + i][col + j] == num)
{
return 0;
}
}
}
return 1;
}
int isValid (char ** Mat, int row, int col, int num)
{
return (checkRow(Mat, row, num) && checkCol(Mat, col, num) && check3x3(Mat, row, col, num));
}
int checkIfPuzzleSolved (char ** Mat, int *row, int *col) // if function finds a box empty (puzzle not solved) returns 0 else returns 1
{
for (*row = 0; *row < 9; *row++)
{
for (*col = 0; *col < 9; *col++)
{
printf("ROW: %d COL: %d\n",*row,*col);
if (Mat[*row][*col] == 0)
{
return 0;
}
}
}
return 1;
}
int solvePuzzle (char ** Mat)
{
int row;
int col;
if (checkIfPuzzleSolved(Mat, &row, &col))
{
return 1;
}
int num;
for (num = 1; num <= 9; num++)
{
//if (checkRow (Mat,row,num) && checkCol (Mat,col,num) && check3x3 (Mat,row,col,num))
if (isValid(Mat, row, col, num))
{
Mat[row][col] = num;
if (solvePuzzle(Mat))
return 1;
Mat[row][col] = 0;
}
}
return 0;
}
调试器在这个函数中发现了一个错误:
int checkIfPuzzleSolved (char ** Mat, int *row, int *col) // if function finds a box empty (puzzle not solved) returns 0 else returns 1
{
for (*row = 0; *row < 9; *row++)
{
for (*col = 0; *col < 9; *col++)
{
printf("ROW: %d COL: %d\n",*row,*col);
if (Mat[*row][*col] == 0) /* DEBUGGER ERROR CODE 0xC0000005: Access violation reading location 0xCDCA247C
{
return 0;
}
}
}
return 1;
}
让我困惑的两件事:
1) 我不明白solvePuzzle 在拼图中的第一个框(第一行第一列)被卡住的原因。似乎checkIfPuzzleSolved 认为第一个框是空的(包含 0),即使使用 printSudoku 我可以看到修改该框的算法在 3 和 4 之间切换它的值,显然 0 != 3 和 0 != 4 .
2) 在checkIfPuzzleSolved,printf 在屏幕上打印行号和列号并不断产生以下结果:
ROW: 0 COL: 0
ROW: 0 COL: 0
ROW: 0 COL: -858993460
还用调试器仔细检查过,这些值确实是提到的。
我的思路如下:
1) 使用checkIfEmpty 判断谜题中是否包含0,表示谜题还没有解开。 row 和 col 变量是通过引用传入函数的,所以当函数找到一个空框并返回时,row 和 col 会保存空框的坐标。
2) 在循环中,调用checkRow、checkCol 和check3x3 以检查是否可以在不违反数独规则的情况下将数字放入所需的框中。 isValid 是为了便于阅读。
3) 递归调用solvePuzzle,直到解开谜题,同时如果一个数错了,将其重置为0。
我已经尝试了我能想到的一切来解决这个问题,浪费了几个小时一遍又一遍地阅读我的代码以找到一个逻辑错误,但一切似乎都很好。有什么想法吗?
编辑:根据 Michael Beer 的要求,这是一个示例二进制文件:
data.bin
142156177191216228257289311329364375418422441484534546562579625663682698739743787794824855883896917933951968
【问题讨论】:
-
*row++;解析为*(row++);,相当于row++。您正在增加指针,而不是计数器。 -
@melpomene 我明白了。那么我是否将指针增加 sizeof(int) 而不是将其引用的值增加 1?如果是这样,关于语法,编写“将您指向的地址的值增加 1”的正确方法是什么?
-
@JohnM。
(*row)++或++(*row)或++*row或*row += 1。 -
@melpomene 谢谢,这解决了问题。如果您想将其作为官方答案,我可以接受并投票。顺便说一句, *row++ 不应该从右到左优先并被评估为 (*row)++ 吗?我以为是这样的。
-
否,后缀运算符(
++、--、[]、()、->foo、.foo)的优先级高于前缀运算符。
标签: c