损坏的双向链接列表

损坏的双向链接列表

我正在做一个学校项目,需要从文件中获取矩阵信息(高度,宽度,单元状态)。像这样:

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$

10-02 14:45