我正在做一个学校项目,需要从文件中获取矩阵的信息(高度、宽度、单元格状态)。类似这样的东西:
30 40 /*height and width*/
3 /*nr of lines to read from the file*/
10 11 1 /*coordinates, and cell status (0,1,2)*/
10 12 1
10 13 2
出于某种原因,它一直在调试器或损坏的双链接列表中给我SIGABRT。我知道代码并没有尽可能完美,但我开始修改它,看看是否能找到问题。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int ***getFileLoad(char *fileName)
{
char strLines[5], strColumns[5], strCells[5], strTemp[3];
int i = 0, j = 0, k = 0, l = 0, lines = 0, columns = 0, cells = 0, intTemp = 0;
int ***array = NULL;
FILE *file = NULL;
file = fopen(fileName, "r"); /*opens file*/
if (file == NULL)
{
printf("Error opening file!n");
exit(EXIT_FAILURE);
}
fscanf(file, "%s %s %s", &strLines, &strColumns, &strCells);
lines = atoi(strLines);
if (lines <= 0) /*lines*/
{
printf("Invalid value, lines!");
exit(EXIT_FAILURE);
}
columns = atoi(strColumns);
if (columns <= 0) /*columns*/
{
printf("Invalid value, columns!");
exit(EXIT_FAILURE);
}
cells = atoi(strCells);
if (cells <= 0) /*cells*/
{
printf("Invalid value, cells!");
exit(EXIT_FAILURE);
}
array = (int ***)malloc(sizeof(int **) * lines); /*allocating lines*/
if (array == NULL)
{
printf("No memory!");
exit(EXIT_FAILURE);
}
for (i = 0; i < columns; i++) /*allocating columns*/
{
array[i] = (int **)malloc(sizeof(int *) * columns);
if (array[i] == NULL)
{
printf("No memory!");
for (j = 0; j < i; j++)
{
free(array[j]);
}
free(array);
array = NULL;
exit(EXIT_FAILURE);
}
}
for (i = 0; i < lines; i++) /*allocating nr of cells*/
{
for (j = 0; j < columns; j++)
{
array[i][j] = (int *)malloc(sizeof(int) * cells);
if (array[i][j] == NULL)
{
printf("No memory!");
for (k = 0; k < i; k++)
{
for (l = 0; l < j; l++)
{
free(array[k][l]);
}
}
for (k = 0; k < i; k++)
{
free(array[k]);
}
free(array);
array = NULL;
exit(EXIT_FAILURE);
}
}
}
array[0][0][0] = lines;
array[0][0][1] = columns;
array[0][0][2] = cells;
for (i = 0; i < 1; i++) /*nr arrays*/
{
for (j = 1; j < cells + 1; j++) /*nr cells*/
{
for (k = 0; k < 4; k++) /*values from file*/
{
if (k == 3) /*getting to the next line*/
{
intTemp = fgetc(file);
if (intTemp == 'n' || intTemp == EOF)
{
continue;
}
else
{
while (intTemp != 'n' || intTemp != EOF)
{
intTemp = fgetc(file);
if (intTemp == 'n' || intTemp == EOF)
{
break;
}
}
}
}
else
{
fscanf(file, "%s", strTemp);
if (isdigit(strTemp))
{
intTemp = atoi(strTemp);
if (k == 0) /*accepting lines with values between1->lines*/
{
if (!(intTemp >= 1 && intTemp < lines))
{
printf("Invalid value!");
exit(EXIT_FAILURE);
}
else
{
array[i][j][k] = intTemp;
}
}
else if (k == 1) /*accepting columns with values between 1->columns*/
{
if (!(intTemp >= 1 && intTemp < columns))
{
printf("Invalid value!");
exit(EXIT_FAILURE);
}
else
{
array[i][j][k] = intTemp;
}
}
else if (k == 2) /*accepting cells with values between 0->2*/
{
if (!(intTemp >= 0 && intTemp < 3))
{
printf("Invalid value!");
exit(EXIT_FAILURE);
}
else
{
array[i][j][k] = intTemp;
}
}
}
}
}
}
}
intTemp = fgetc(file); /*checking for EOF*/
if (intTemp != EOF)
{
printf("Impossible reading every value!");
exit(EXIT_FAILURE);
}
fclose(file);
return array;
}
基本问题与这些类型的问题通常相同-你的任务对自己来说太复杂了,原因是:
-
在一个巨大的函数中填充太多,而不是将其分解为可消化的片段
-
使用像
fscanf()
和fgetc()
这样笨拙的文件读取功能 -
重复代码,包括可以转移到单独功能的错误检查代码
所有这些都使得跟踪你正在做的事情变得极其困难,因为你庞大的函数读起来像意大利面条,而你对它没有全局的看法。它变成了一大堆代码,任何一个都可能是错误的。
以下是一些操作的示例,您可以也应该具有单独的功能:
-
创建矩阵
-
摧毁你的矩阵
-
设置矩阵单元格的值
-
获取矩阵单元格的值
-
从文件中获取一组坐标
-
从文件中获取尺寸
-
从文件中获取行数
此外,您应该将相关值封装在数据结构中,例如矩阵的维度(以及矩阵数据本身的维度)和坐标。
下面是一个更好的编写方法的快速示例。例如,看看main()
函数,看看它有多容易理解。如果你的代码很容易理解,那么它就很容易维护,也更容易发现(和避免)错误。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_LINE_LENGTH 1024
/* Holds dimensions for a matrix */
struct dimensions {
int lines;
int columns;
int cells;
};
/* Holds a set of three-dimensional coordinates */
struct coords {
int x;
int y;
int z;
};
/* Holds a three-dimensional matrix */
struct matrix {
struct dimensions dim;
int *** lines;
};
void * xmalloc(const size_t sz);
void * xcalloc(const size_t nmemb, const size_t size);
struct matrix * matrixCreate(struct dimensions * dim);
void matrixDestroy(struct matrix * matrix);
void matrixSet(struct matrix * matrix, struct coords coord, const int value);
int matrixGet(struct matrix * matrix, struct coords coord);
FILE * openDataFile(const char * filename);
void getLineFromFile(FILE * fp, char * buffer, const size_t length);
struct dimensions getDimensionsFromFile(FILE * fp);
struct coords getCoordsFromFile(FILE * fp);
void validateCoords(struct matrix * matrix, struct coords coords);
int getSingleIntegerLine(FILE * fp);
int main(void)
{
/* Set up matrix and data file */
FILE * fp = openDataFile("matrix.dat");
struct dimensions dim = getDimensionsFromFile(fp);
const int numLines = getSingleIntegerLine(fp);
struct matrix * matrix = matrixCreate(&dim);
/* Populate matrix cells specified in file */
for ( size_t i = 0; i < numLines; ++i ) {
struct coords coords = getCoordsFromFile(fp);
validateCoords(matrix, coords);
matrixSet(matrix, coords, 1);
}
/* Test and print the value of some matrix cells */
struct coords coords[6] = {
{10, 11, 1},
{10, 11, 2},
{10, 12, 1},
{10, 12, 2},
{10, 13, 1},
{10, 13, 2}
};
for ( size_t i = 0; i < 6; ++i ) {
const int value = matrixGet(matrix, coords[i]);
printf("Value at %d, %d, %d: %dn",
coords[i].x, coords[i].y, coords[i].z, value);
}
/* Clean up and exit */
matrixDestroy(matrix);
fclose(fp);
return 0;
}
void * xmalloc(const size_t sz)
{
void * p = malloc(sz);
if ( !p ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
return p;
}
void * xcalloc(const size_t nmemb, const size_t size)
{
void * p = calloc(nmemb, size);
if ( !p ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
return p;
}
struct matrix * matrixCreate(struct dimensions * dim)
{
int *** lines = xmalloc(dim->lines * sizeof *lines);
for ( size_t i = 0; i < dim->lines; ++i ) {
int ** columns = xmalloc(dim->columns * sizeof *columns);
for ( size_t j = 0; j < dim->columns; ++j ) {
int * cells = xcalloc(dim->cells, sizeof *cells);
columns[j] = cells;
}
lines[i] = columns;
}
struct matrix * matrix = xmalloc(sizeof *matrix);
matrix->lines = lines;
matrix->dim = *dim;
return matrix;
}
void matrixDestroy(struct matrix * matrix)
{
for ( size_t i = 0; i < matrix->dim.lines; ++i ) {
for ( size_t j = 0; j < matrix->dim.columns; ++j ) {
free(matrix->lines[i][j]);
}
free(matrix->lines[i]);
}
free(matrix->lines);
free(matrix);
}
void matrixSet(struct matrix * matrix, struct coords coords, const int value)
{
matrix->lines[coords.x][coords.y][coords.z] = value;
}
int matrixGet(struct matrix * matrix, struct coords coords)
{
return matrix->lines[coords.x][coords.y][coords.z];
}
FILE * openDataFile(const char * filename)
{
FILE * fp = fopen(filename, "r");
if ( !fp ) {
perror("couldn't open file");
exit(EXIT_FAILURE);
}
return fp;
}
void getLineFromFile(FILE * fp, char * buffer, const size_t length)
{
if ( !fgets(buffer, length, fp) ) {
fprintf(stderr, "Couldn't read dimensions from file.n");
exit(EXIT_FAILURE);
}
}
struct dimensions getDimensionsFromFile(FILE * fp)
{
char buffer[MAX_LINE_LENGTH];
getLineFromFile(fp, buffer, MAX_LINE_LENGTH);
struct dimensions dim;
if ( sscanf(buffer, "%d %d", &dim.lines, &dim.columns) != 2 ) {
fprintf(stderr, "Couldn't read dimensions from file.n");
exit(EXIT_FAILURE);
}
dim.cells = 3;
return dim;
}
struct coords getCoordsFromFile(FILE * fp)
{
char buffer[MAX_LINE_LENGTH];
getLineFromFile(fp, buffer, MAX_LINE_LENGTH);
struct coords coords;
if ( sscanf(buffer, "%d %d %d", &coords.x, &coords.y, &coords.z) != 3 ) {
fprintf(stderr, "Couldn't read coordinates from file.n");
exit(EXIT_FAILURE);
}
return coords;
}
void validateCoords(struct matrix * matrix, struct coords coords)
{
bool valid = true;
if ( coords.x < 0 || coords.x >= matrix->dim.lines ) {
fprintf(stderr, "Invalid x coordinate: %dn", coords.x);
valid = false;
}
if ( coords.y < 0 || coords.y >= matrix->dim.columns ) {
fprintf(stderr, "Invalid y coordinate: %dn", coords.y);
valid = false;
}
if ( coords.z < 0 || coords.z >= matrix->dim.cells ) {
fprintf(stderr, "Invalid z coordinate: %dn", coords.z);
valid = false;
}
if ( !valid ) {
exit(EXIT_FAILURE);
}
}
int getSingleIntegerLine(FILE * fp)
{
char buffer[MAX_LINE_LENGTH];
getLineFromFile(fp, buffer, MAX_LINE_LENGTH);
int value;
if ( sscanf(buffer, "%d", &value) != 1 ) {
fprintf(stderr, "Couldn't read single value from file.n");
exit(EXIT_FAILURE);
}
return value;
}
使用您的示例文件:
paul@thoth:~/src/sandbox$ ./matrix
Value at 10, 11, 1: 1
Value at 10, 11, 2: 0
Value at 10, 12, 1: 1
Value at 10, 12, 2: 0
Value at 10, 13, 1: 0
Value at 10, 13, 2: 1
paul@thoth:~/src/sandbox$
我不确定,但当变量j引用的数组大小为i3时,您可以将其从0循环到3。可能来自:的长宁86号线
for (j = 1; j<cells + 1; j++) { /*nr cells*/
至:
for (j = 1; j<cells; j++) { /*nr cells*/
将解决问题。