尝试在 C 中读取迷宫文本文件时出现 malloc 错误 [英] malloc error when trying to read a maze text file in C

查看:15
本文介绍了尝试在 C 中读取迷宫文本文件时出现 malloc 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试让我的代码从内容涉及的文本文件中读取:(文本文件名为maze1.txt)

I'm trying to get my code to read from a text file that's contents involve: (text file is called maze1.txt)

5 5
%%%%%
S % %
% % %
%   E
%%%%%

但是,每当我尝试运行程序时,我都会收到 分段错误,我认为这与我使用 malloc 的方式有关.我知道我已经使用第一个数字来为我的数组设置边界,但我不确定如何做到这一点.

However whenever I attempt to run the program I receive a segmentation fault which I think has something to do with how I'm using malloc. I know that I have use the first numbers in order to set boundaries for my array, but I'm unsure on how to do that.

提供的是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include "maze.h"
maze_t * createMaze(char * fileName)
{
    typedef struct Maze{
    int cols, rows;
    char **charRow;
    }MAZE;
    struct Maze maze;
    FILE *pf;
    int i,j,k;
    pf = fopen(fileName,"r");
    k = fscanf(pf, "%i %*c %i", &maze.cols, &maze.rows);
    char cMaze[maze.cols][maze.rows];
    int new;
    int *newMaze = (int *)malloc( maze.rows * maze.cols * sizeof(int));
    for(i = 0; maze.rows; i++){
        for(j = 0; j < maze.cols; j++){
            cMaze[i][j] = fgetc(pf);
            putchar( cMaze[i][j] ); 

        }       
    }
    printf("%d", cMaze[maze.cols][maze.rows]);
    printf("
");
    maze.charRow = newMaze;
    fclose(pf);


    return newMaze;
}

这是我的主要内容:

#include <stdio.h>
#include "maze.h"


int main(int argc, char **argv)
{
    if (argc < 2)
    {
        printf("You need a valid input maze file.
");
        return -1;
    }

    printf("Creating maze with file %s
", argv[1]);
    maze_t * maze = createMaze(argv[1]);

    printf("
Unsolved maze:
");
    printMaze(maze);

    if(solveMazeManhattanDFS(maze, maze->startColumn, maze->startRow))
    {
        printf("
Solved maze:
");
        printMaze(maze);
        if(checkMaze(maze))
        {
            printf("Solution to maze is valid
");
        }
        else
        {
            printf("Incorrect solution to maze
");
        }
    }
    else
    {
        printf("
Maze is unsolvable
");
    }

    printf("
Destroying maze
");

    destroyMaze(maze);

    return 0;
}

结构体maze_t的定义是

definition of the struct maze_t is

typedef struct {
    int width;
    int height;
    int startColumn;
    int startRow;
    int endColumn;
    int endRow;
    char ** cells;
} maze_t;

推荐答案

您无法知道 createMaze 是成功还是失败,因为您无法验证您的文件是否实际上已打开以供读取.当您保存 fscanf 的返回时,您无法以任何方式验证实际发生了 2 次转换.

You have no way to know whether createMaze succeeds or fails because you fail to validate that your file is actually open for reading. While you save the return of fscanf, you fail to validate in any way that 2 conversions actually took place.

对第一行使用 fscanf 没问题,但要了解 ' ' 留在 stdin 中,您必须考虑在你下次阅读之前.(您的下一个读取是 fgetc - 它会很乐意将 ' ' 作为文件中的下一个值并将其分配给 cMaze[0][0].

Using fscanf is fine for the first row, but understand that the ' ' is left in stdin and you must account for that before your next read. (your next read being fgetc -- it will happily take ' ' as the next value in the file and assign it to cMaze[0][0].

二维数组等同于 char **.如果您打算存储构成迷宫的行并通过 char **charRow; 引用它们,那么您需要分配 maze.rows 个指向 char 的指针,然后您需要为每一行分配存储并将该存储块的起始地址分配给每个 maze.charRow[x].(对于面向行的输入,fgets 是读取每一行的更好选择)

A 2D array is not equivalent to char **. If you plan on storing the lines that make up the maze and referencing them through char **charRow;, then you need to allocate maze.rows number of pointers to char, and you then need to allocate storage for each line and assign the beginning address for that block of storage to each maze.charRow[x]. (for line oriented input, fgets is a better choice for reading each line)

您为 newMaze 分配,但不分配任何值.

You allocate for newMaze, but do not assign any values.

让我提供一个示例来正确验证您需要采取的每个步骤,而不是为您修复现有代码,将每一行存储在 maze.line[x] (您重命名的 charRow),使用存储的值输出迷宫,然后在退出之前释放所有分配的内存(每行 + 指针).每个单独的验证都在下面的注释中进行了描述,例如

Rather than fixing your existing code for you, let me provide an example that properly validates each step you need to take, stores each line in maze.line[x] (your renamed charRow), outputs the maze using the stored values and then frees all memory allocated (each line + the pointers) before exiting. Each individual validation is described in the comments, in-line, below, e.g.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#ifndef BUF_SIZ
#define BUF_SIZ 8192
#endif

typedef struct {
    int cols, rows;
    char **line;
} maze_t;

void *xcalloc (size_t nmemb, size_t sz);

int main (int argc, char **argv) {

    char buf[BUF_SIZ] = "";
    int n = 0;
    maze_t maze;
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        fprintf (stderr, "error: file open failed '%s'.
", argv[1]);
        return 1;
    }

    /* read maze.rows & maze.cols */
    if (fscanf (fp, "%d %d", &maze.rows, &maze.cols) != 2) {
        fprintf (stderr, "error: failed to read rows & cols.
");
        return 1;
    }
    fgets (buf, BUF_SIZ, fp);   /* read discard any additional chars */

    /* allocate/validate maze.rows pointers */
    maze.line = xcalloc (maze.rows, sizeof *maze.line);

    /* read each remaining line up to maze.rows lines */
    while (n < maze.rows && fgets (buf, BUF_SIZ, fp)) {
        size_t len = strlen (buf);      /* get buf length */
        if (len && buf[len-1] == '
')  /* validate last char is '
' */
            buf[--len] = 0;             /* overwrite with nul-character */
        else {      /* line too long, handle error */
            fprintf (stderr, "error: line exceeds BUF_SIZ.
");
            return 1;
        }
        if (len != (size_t)maze.cols) { /* validate maze.cols chars read */
            fprintf (stderr, "error: line exceeds maze.cols.
");
            return 1;
        }

        /* allocate/validate maze.cols +1 chars */
        maze.line[n] = xcalloc (len + 1, sizeof *maze.line[n]);
        strcpy (maze.line[n++], buf);   /* copy buf to maze.line[n] */
    }

    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    if (n != maze.rows) {   /* validate maze.rows lines read */
        fprintf (stderr, "error: less than maze.rows lines read.
");
        return 1;
    }

    for (int i = 0; i < n; i++) {
        printf ("%s
", maze.line[i]);  /* output each line */
        free (maze.line[i]);            /* free line */
    }
    free (maze.line);                   /* free pointers */

    return 0;
}

/** xcalloc allocates memory using calloc and validates the return.
 *  xcalloc allocates memory and reports an error if the value is
 *  null, returning a memory address only if the value is nonzero
 *  freeing the caller of validating within the body of code.
 */
void *xcalloc (size_t nmemb, size_t sz)
{
    register void *memptr = calloc (nmemb, sz);
    if (memptr == 0) {
        perror ("xcalloc() error: virtual memory exhausted.");
        exit (EXIT_FAILURE);
    }

    return memptr;
}

希望这将为您需要在代码中更正的每个步骤提供一个工作示例.(注意: xcalloc 函数只是为了方便上面避免重复代码主体中的验证)

Hopefully this will provide a working example of each of the steps you need to correct in your code. (note: the xcalloc function is just for convenience above to keep from duplicating the validations in the body of the code)

使用/输出示例

$ ./bin/maze <dat/maze.txt
%%%%%
S % %
% % %
%   E
%%%%%

内存使用/错误检查

在您编写的任何动态分配内存的代码中,对于分配的任何内存块,您都有 2 个职责:(1)始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放.

In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.

对于 Linux,valgrind 是正常的选择.每个平台都有类似的内存检查器.它们都易于使用,只需通过它运行您的程序即可.

For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.

$ valgrind ./bin/maze <dat/maze.txt
==18822== Memcheck, a memory error detector
==18822== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==18822== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==18822== Command: ./bin/maze
==18822==
%%%%%
S % %
% % %
%   E
%%%%%
==18822==
==18822== HEAP SUMMARY:
==18822==     in use at exit: 0 bytes in 0 blocks
==18822==   total heap usage: 6 allocs, 6 frees, 70 bytes allocated
==18822==
==18822== All heap blocks were freed -- no leaks are possible
==18822==
==18822== For counts of detected and suppressed errors, rerun with: -v
==18822== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放已分配的所有内存并且没有内存错误.

Always confirm that you have freed all memory you have allocated and that there are no memory errors.

仔细检查,努力将验证合并到您的代码中,如果您有任何其他问题,请告诉我.

Look things over, work to incorporate the validations in your code and let me know if you have any further questions.

这篇关于尝试在 C 中读取迷宫文本文件时出现 malloc 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆