SIGABRT和损坏的双链表

时间:2016-01-11 03:15:57

标签: c function multidimensional-array malloc

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

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;
}

2 个答案:

答案 0 :(得分:1)

基本问题与这些类型的问题通常是一样的 - 你通过以下方式使你的任务过于复杂:

  • 在一个巨大的功能中填充太多而不是将其分解成易消化的部分

  • 使用笨拙的文件阅读功能,例如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$ 

答案 1 :(得分:0)

我不确定,但是当数组引用i 3的大小时,你将变量j从0循环到3。也许从第86行开始:

for (j = 1; j<cells + 1; j++) {   /*nr cells*/

为:

for (j = 1; j<cells; j++) {   /*nr cells*/

将解决问题。