从二进制文件读取并分配到矩阵

时间:2018-06-13 19:13:13

标签: c binaryfiles

我有一项任务,创建一个解决9x9数独谜题的程序。规格如下:

  • 必须将文件名作为参数提供给命令行(编辑:argv[0]不是必需的,只需要通过键盘输入scanf功能)
  • 文件必须是二进制文件
  • 必须动态分配所有数组
  • 二进制文件包含用于确定坐标和所需数字的数字 例如367表示第3行第6列和第7列

我的程序动态分配一个2D数组,然后分配空间来保存文件名,然后打开二进制文件来读取数据。使用printf来调试我的程序似乎数据被适当地保存到importedData数组,当在数独谜题上分配这些数据时,程序崩溃,或者没有正确地分配值。这是我的代码:

Sudoku.c

#include <stdio.h>
#include <stdlib.h>
#include "sudokulib.h"

#define MALLOC_ERROR 0xFF
#define FILE_NOT_FOUND 0xFFF

int main(int argc,char ** argv)
{
    char **matrix;
    int i,j; 
    int row,column,num;
    FILE * fp;
    char * filename;
    char * importedData;
    matrix=(char **)malloc(9*sizeof(char *));
    if (!matrix)
    exit(MALLOC_ERROR);
    for (i=0;i<9;++i)
    {
        matrix[i]=(char *)malloc(9*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("%s",filename);
    fp=fopen(filename,"rb");
    if (!fp)
    {
        printf ("File not found\n");
        exit(FILE_NOT_FOUND);
    }
    importedData=(char *)malloc(sizeof(char)*81*3);
    if (!importedData)
    exit (MALLOC_ERROR);
    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')
    {
        row=importedData[i] - 48; /* Convert from ascii code to number */
        column=importedData[i+1] - 48;
        num=importedData[i+2] - 48;
        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

#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-48) 
        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-48) 
        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-48)
            return 0;
        }
    }
    return 1;
}

int checkIfEmpty(char ** Mat, int *row, int *col) // if a block of the entire puzzle is empty returns 1 else returns 0 also saves the target row and column it found empty
{
        for (*row = 0; *row < 9; *row++)
        {
            for (*col = 0; *col < 9; *col++)
            {
                if (Mat[*row][*col] == 0)
                return 1;
            }
        }
    return 0;
}

int solvePuzzle (char ** Mat)
{
    int num;
    int row;
    int col;
    row = 0;
    col = 0;
    if (!checkIfEmpty(Mat,&row,&col)) // if puzzle is solved return 1
    return 1;
    for (num = 1; num < 9; num++)
    {
        if (checkRow (Mat,row,num) && checkCol (Mat,col,num) && check3x3 (Mat,row,col,num))
        {
            Mat[row][col] = num-48;
        }
    if (solvePuzzle (Mat))
    {
        return 1;
    }
    Mat[row][col] = 0;
    }
    return 0;
}

对于解决上述问题的任何帮助表示赞赏。 另请注意,int solvePuzzle()尚未完成,欢迎任何改进此功能的建议。

编辑:以下是导致错误分配的二进制文件data2.bin的内容

142156177191216228257289311329364375418422441484534546562579625663682698739743787794824855883896

输出:

Give me the name of data file: data2.bin
Sudoku after importing data:

-------------------
|0|0|0|0|0|0|0|0|0|
-------------------
|0|0|0|0|2|6|0|7|0|
-------------------
|0|6|8|0|0|7|0|0|9|
-------------------
|0|1|9|0|0|0|4|5|0|
-------------------
|0|8|2|0|1|0|0|0|4|
-------------------
|0|0|0|4|6|0|2|9|0|
-------------------
|0|0|5|0|0|0|3|0|2|
-------------------
|0|0|0|9|3|0|0|0|7|
-------------------
|0|0|4|0|0|5|0|0|3|
-------------------
Press any key to continue . . .

编辑2:发现如果使用包含非常少数据的非常小的二进制文件,例如123245321工作正常,但如果数据超过9个字节,则拼图会搞砸。

1 个答案:

答案 0 :(得分:3)

请注意,数组是零索引的。因此,您需要再减去一个以获得正确的索引,例如:

row=importedData[i] - 48 - 1;

另请注意,您的文件中的数字太少。只有96但你需要243。

...进一步

看看这个:

importedData=(char *)malloc(sizeof(char)*81*3);
...
fread(importedData,1,243,fp);

现在你在importedData中有243个字符(你可以通过查看fread的返回代码来检查。在你的情况下,文件只有96个字符(坏...)但是让& #39; s只是假设它有效。)

然后你做:

    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')
{
    ....
}

因此,如果您阅读的243个字符都使条件高于真,那么您将继续阅读超出为importedData分配的内存。所以你有不确定的行为。

您需要添加:

&& i < 243;

到了条件。

BTW:所有这些硬编码都很糟糕。请改用#define

顺便说一句:不要做

row=importedData[i] - 48 -1;

row=importedData[i] - '0' - 1;