暴力算法会导致未定义的行为

  • 本文关键字:未定义 算法 c
  • 更新时间 :
  • 英文 :


我必须为解决数独难题的任务创建一个程序。用户需要输入包含数字的二进制文件的名称(不是真正的二进制文件,它只有一个.bin扩展名,也可以用记事本、记事本++等打开(。这些数字代表拼图上的坐标以及这些坐标中包含的数字,例如 432 表示第 4 行第 3 列包含数字 2。填写拼图后,我需要解决它并将其打印在屏幕上。执行程序后它崩溃了,所以我决定使用 MSVC 2017 调试器,根据一些开发人员的说法,它是查找和修复该错误的最好的调试器之一。这是我的代码:

数独

#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 foundn");
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:nn");
printSudoku(matrix);
system("pause");
if (solvePuzzle(matrix))
{
printSudoku(matrix);
}
else
printf ("Puzzle has no solutionn");
fclose(fp);
free(filename);
for (i = 0; i<9; ++i)
{
free(matrix[i]);
}
free(matrix);
return 0;
}

数独

#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: %dn",*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: %dn",*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 将保存空框的坐标。

2(在循环中,调用checkRowcheckColcheck3x3,以检查是否可以在不违反数独规则的情况下将号码放入所需的框中。isValid是为了提高可读性。

3(递归调用solvePuzzle直到谜题解决,同时如果数字错误,将其重置为0。

我已经尝试了我能想到的一切来解决这个问题,浪费时间一次又一次地阅读我的代码以找到逻辑错误,但一切似乎都很好。有什么想法吗?

编辑:应迈克尔比尔的要求,这是一个示例二进制文件:

data.bin

142156177191216228257289311329364375418422441484534546562579625663682698739743787794824855883896917933951968

*row++;解析为*(row++);,相当于row++。您正在增加指针,而不是计数器。 - 美尔波美尼

明白了。那么我是否将指针递增了 sizeof(int( 而不是将它引用的值增加了 1?如果是这样,关于语法的"将您指向的地址的值增加 1"的正确编写方法是什么?

(*row)++++(*row)++*row*row += 1。 - 美尔波美尼

最新更新