我必须为解决数独谜题的作业创建一个程序。用户需要输入包含数字的二进制文件的名称(不是真正的二进制文件,它只有.bin扩展名,也可以用记事本,记事本++等打开)。这些数字表示拼图上的坐标以及这些坐标中包含的数字,例如432表示第4行第3列包含数字2.填写拼图后,我需要解决它并在屏幕上打印。在执行程序后它崩溃了,所以我决定使用MSVC 2017调试器,根据一些开发人员找到并修复bug是最好的。这是我的代码:
Sudoku.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;
}
Sudokulib.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
被困在强制谜题中的第一个框(第1行第1列)的原因。似乎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
答案 0 :(得分:1)
*row++;
parses as *(row++);
, which is equivalent to just row++
. You're incrementing the pointer, not the counter.
– melpomene
I see. So am I incrementing the pointer by sizeof(int) and not increasing the value that it refers to by 1? If so what is the correct way of writing "increment the value of the address you are pointing to by 1" regarding the syntax?
(*row)++
or ++(*row)
or ++*row
or *row += 1
.
– melpomene