Ошибка сегментации на C Причина Fgetc () - PullRequest
0 голосов
/ 08 марта 2019

Я пытаюсь кодировать алгоритм поиска пути в C. Я пытаюсь отсканировать карту, в которой пытаюсь найти кратчайший путь, и помещаю его в двумерный динамический массив.

Это моя основная карта:

5 5
11111
01001
00101
00010
00001

5 - количество строк, а остальные 5 - количество столбцов.И 1 - это путь, 0 - это стена.Это мой код:

#include <stdio.h>
#include <stdlib.h>
int row;
int column;

void main()
{
    FILE *fp;
    int **array;
    fp = fopen("file.path", "r");
    fscanf(fp, "%d", &row);
    fgetc(fp);
    fscanf(fp, "%d", &column);
    array = (int **)malloc(row * sizeof(int));
    for(int i=0; i<row; i++)
        array[i] = malloc(column * sizeof(int));

    for(int i=0; i<row; i++)
    {
        for(int j=0; j<column; j++)
        {
            char tmp = fgetc(fp);
            array[i][j] = (tmp - '0');
        }
    }
}

и этот код возвращает ошибку сегментации.

Ответы [ 2 ]

1 голос
/ 08 марта 2019

этот код возвращает ошибку сегментации.

см. Примечание о malloc ниже


Некоторые замечания сверху внизкод

В

int row;
int column;

Почему эти две глобальные переменные?они могут быть локальными в main

В

fp = fopen("file.path", "r");
fscanf(fp, "%d", &row);
fgetc(fp);
fscanf(fp, "%d", &column);

необходимо проверить, что fp не равно NULL, чтобы бытьубедитесь, что при открытии

вам нужно проверить, что fscanf возвращает 1, чтобы убедиться, что вы смогли прочитать число

fgetc между нимибесполезно, пробел будет обойден вторым fscanf

примечанием, что вы можете сделать уникальный fscanf , чтобы прочитать два числа:

if (fscanf(fp, "%d %d", &row, &column) != 2) {
  ... manage error to not continue the execution
}

В

 array = (int **)malloc(row * sizeof(int));

, как сказано в комментариях, вы выделяете массив int*, а не массив int , который объясняет вашу ошибку сегментации позжев исполнении (вы явно в 64b) приведение бесполезно, поэтому array = malloc(row * sizeof(int*));

Вам также нужно проверить, что malloc не возвращает NULL

In

       char tmp = fgetc(fp);
        array[i][j] = (tmp - '0');

tmp должен быть int , чтобы иметь возможность проверить регистр EOF

Обратите внимание, что вы также можете читать строку, а не символ за символом

Предупреждение кр tmp получает переводы строк, поэтому вы неправильно инициализируете массив


Предложение:

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

int main()
{
    FILE *fp;
    int ** array;
    int row;
    int column;

    fp = fopen("file.path", "r");
    if (fp == NULL) {
      puts("cannot open file.path");
      return -1;
    }

    if (fscanf(fp, "%d %d", &row, &column) != 2) {
      puts("cannot read row column");
      fclose(fp);
      return -1;
    }

    array = malloc(row * sizeof(int*));

    if (array == NULL) {
      puts("not enough memory");
      fclose(fp);
      return -1;
    }

    for (int i=0; i<row; i++) {
      array[i] = malloc(column * sizeof(int));
      if (array[i] == NULL) {
        puts("not enough memory");
        fclose(fp);
        return -1;
      }
    }

    for (int i=0; i<row; i++)
    {
      /* finish to read previous line */
      int c;

      while ((c = fgetc(fp)) != '\n') {
        if (c == EOF) {
          fclose(fp);
          puts("unexpected EOF");
          return -1;
        }
      }

      for(int j=0; j<column; j++)
      {
        c = fgetc(fp);

        if (c == EOF) {
          puts("unexpected EOF");
          fclose(fp);
          return -1;
        }
        if ((c != '0') && (c != '1')) {
          puts("invalid value");
          fclose(fp);
        }

        array[i][j] = (c - '0');
      }
    }
    fclose(fp);

    /* show the content for at least debug */
    puts("array is:");

    for (int i=0; i<row; i++)
    {
      for (int j=0; j<column; j++)
        printf("%d ", array[i][j]);
      putchar('\n');
    }

    /* free resources */
    for (int i=0; i<row; i++)
    {
      free(array[i]);
    }
    free(array);
}

Компиляция и выполнение:

pi@raspberrypi:~ $ gcc -pedantic -Wextra b.c
pi@raspberrypi:~ $ cat file.path 
5 5
11111
01001
00101
00010
00001
pi@raspberrypi:~ $ ./a.out
array is:
1 1 1 1 1 
0 1 0 0 1 
0 0 1 0 1 
0 0 0 1 0 
0 0 0 0 1 
pi@raspberrypi:~ $ 

Выполнение под valgrind :

pi@raspberrypi:~ $ valgrind ./a.out
==4841== Memcheck, a memory error detector
==4841== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4841== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4841== Command: ./a.out
==4841== 
array is:
1 1 1 1 1 
0 1 0 0 1 
0 0 1 0 1 
0 0 0 1 0 
0 0 0 0 1 
==4841== 
==4841== HEAP SUMMARY:
==4841==     in use at exit: 0 bytes in 0 blocks
==4841==   total heap usage: 9 allocs, 9 frees, 5,592 bytes allocated
==4841== 
==4841== All heap blocks were freed -- no leaks are possible
==4841== 
==4841== For counts of detected and suppressed errors, rerun with: -v
==4841== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

Примечание: я использую fscanf затем fgetc и из-за смеси необходимо управлятьnewline, другой способ - всегда использовать getline для чтения строки в строке и для dims для использования sscanf

0 голосов
/ 08 марта 2019

Он компилируется и запускается в моем тесте (с использованием VC ++ 2017) без segfault, вам нужно запустить его в отладчике, чтобы определить, где и почему он выходит из строя на вашей цели.

Однако код неправильный или опрометчивый несколькими способами, которые вы должны исправить в любом случае.

  • Не удастся выделить правильное количество места на цели, где sizeof(int) != sizeof(int*).
  • Ваша карта будет загружена неправильно, поскольку вы не работали с символами новой строки, в том числе после первой строки 5 5.
  • fgetc(fp); между двумя fscanf, это не имеет смысла, так как fscanf() в любом случае отбрасывает начальные пробелы.
  • row и column являются излишне глобальными.
  • У вас нет ошибок при проверке.
  • При литье в C malloc() не требуется или не рекомендуется.

Рассмотрим:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int main()
{
    FILE* fp = fopen("file.path", "r") ;

    if( fp != 0 )
    {
        int row = 0;
        int column = 0;
        int check = fscanf( fp, "%d%d\n", &row, &column ) ;

        if( check == 2 )
        {
            bool map_valid = false;
            int** array = malloc( row * sizeof(*array) ) ;
            if( array != NULL )
            {   
                map_valid = true ;
                for( int i = 0; map_valid && i < row ; i++ )
                {
                    array[i] = malloc( column * sizeof(*array[i]) ) ;
                    map_valid = (array[i] != NULL) ;
                }
            }

            for( int i = 0; map_valid && i < row; i++ )
            {
                int c = 0 ;
                for( int j = 0; map_valid && j < column; j++ )
                {
                    c = fgetc(fp);
                    map_valid = c != EOF ;
                    array[i][j] = (c - '0');
                }
                    while( map_valid  && (c = fgetc(fp)) != '\n' && c != EOF ){}
            }

            if( map_valid )
            {
                // ...
            }

            if( array != NULL )
            {
                for( int i  = 0; i < row; i++ )
                {
                    if( array[i] != NULL )
                    {
                        free( array[i] ) ;
                    }
                }
                free( array ) ;
            }
        }
    }

    return 0 ;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...