malloc error when trying to read a maze text file in C [closed]

為{幸葍}努か 提交于 2019-12-03 01:08:04

问题


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
%%%%%

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.

provided is my code:

#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("\n");
    maze.charRow = newMaze;
    fclose(pf);


    return newMaze;
}

and here is my main:

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


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

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

    printf("\nUnsolved maze:\n");
    printMaze(maze);

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

    printf("\nDestroying maze\n");

    destroyMaze(maze);

    return 0;
}

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;

回答1:


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.

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

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)

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

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'.\n", 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.\n");
        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] == '\n')  /* validate last char is '\n' */
            buf[--len] = 0;             /* overwrite with nul-character */
        else {      /* line too long, handle error */
            fprintf (stderr, "error: line exceeds BUF_SIZ.\n");
            return 1;
        }
        if (len != (size_t)maze.cols) { /* validate maze.cols chars read */
            fprintf (stderr, "error: line exceeds maze.cols.\n");
            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.\n");
        return 1;
    }

    for (int i = 0; i < n; i++) {
        printf ("%s\n", 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;
}

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)

Example Use/Output

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

Memory Use/Error Check

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.

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.




回答2:


I think your problem is this line:

k = fscanf(pf, "%i %*c %i", &maze.cols, &maze.rows);

With the input

5 5

you'll not get maze.rows initialized. The %*c will "eat" (supress) the second 5.

Try this to debug your code:

k = 0;
maze.cols = 0;
maze.rows = 0;
k = fscanf(pf, "%i %*c %i", &maze.cols, &maze.rows);
printf("%d %d %d\n", k, maze.cols, maze.rows);

and check the values printed. I get the values:

1 5 0

so maze.rows wasn't assigned by the fscanf

After that try this instead:

k = fscanf(pf, "%i %i", &maze.cols, &maze.rows);



回答3:


You need to read properly row and column numbers like below.

k = fscanf(pf, "%d %d", &maze.cols, &maze.rows);

Also, your for statement has some mistakes. It must be like this.

for (i = 0; i <= maze.rows; i++) {
    for (j = 0; j <= maze.cols; j++) {
        cMaze[i][j] = fgetc(pf);
        putchar(cMaze[i][j]);
    }
}

Edit: Try the code I wrote for your createMaze. If you don't understand feel free to ask more questions.

struct 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, "%d %d", &maze.cols, &maze.rows);
    int *newMaze = (int *)malloc(maze.rows * maze.cols * sizeof(int));
    for (i = 0; i <= maze.rows; i++) {
        for (j = 0; j <= maze.cols; j++) {
            newMaze[i+j] = fgetc(pf);
            putchar(newMaze[i+j]);
        }
    }
    printf("\n");
    fclose(pf);

    return newMaze;
}


来源:https://stackoverflow.com/questions/47235221/malloc-error-when-trying-to-read-a-maze-text-file-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!