我正在做一个学校项目,需要从文件中获取矩阵信息(高度,宽度,单元状态)。像这样:
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: %d\n",
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: %d\n", coords.x);
valid = false;
}
if ( coords.y < 0 || coords.y >= matrix->dim.columns ) {
fprintf(stderr, "Invalid y coordinate: %d\n", coords.y);
valid = false;
}
if ( coords.z < 0 || coords.z >= matrix->dim.cells ) {
fprintf(stderr, "Invalid z coordinate: %d\n", 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$