Ошибка сегментации с использованием fscanf в C - PullRequest
0 голосов
/ 07 июня 2019

Я пытаюсь прочитать имена из текстового файла в моем коде для .c, но я продолжаю получать ошибку сегментации от fscanf и, похоже, не могу выяснить, в чем проблема.

Я пробовал несколько вариантов, включая увеличение размера массива символов, но я понятия не имею, что не так, любая помощь будет оценена.

Я также выполнил это в DevC ++, и это сработало, но когда я использовал gcc, это дало мне ошибку segfault.

в основном

FILE* infile;
char buffer[20];

в корпусе переключателя в главном

infile = fopen("pathway", "r");
for (i=-1; i < name; i++)
{
     fscanf(infile, "%s", buffer);
}
fclose(infile);

файл

Zeda'Taxu
Khano'Balme
Goni
...
...

Ответы [ 2 ]

1 голос
/ 07 июня 2019

Необходимо сделать пару замечаний (1) никогда не экономить на размере буфера .20 ужасно недостаточно для большого процента используемых имен.64 может быть разумного размера, и затем вы берете этот разумный размер и double it.

Далее, (2) неясно, что name делает в вашем коде, нотак как он используется в ограничении цикла for, это число имен, которыми вы хотите ограничить чтение.Вы должны контролировать свой цикл чтения, чтобы он завершался, когда 1 - ваш индекс чтения не меньше, чем ваш name limit && fgets () возвращает действительный указатель, например

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

#define MAXNM 128   /* if you need a constant, #define one (or more) */
#define NUMNM  10   /*        ( Don't skimp on buffer size! )        */

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

    char buffer[MAXNM];
    size_t ndx = 0, name = NUMNM;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    ...
    while (ndx < name && fgets (buffer, MAXNM, fp)) {
        buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
        fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
    }

Выше простого *Переменная 1016 * (index) используется вместе с возвратом из fgets для управления циклом чтения.Это устраняет вашу проблему с наличием в файле меньшего количества строк, чем names, но затем вслепую подталкивает чтение из потока в состоянии ошибки до тех пор, пока не будут выполнены итерации name.Используя ndx < NUMNM && fgets (buf, MAXC, fp) в качестве элемента управления циклом, вы корректно завершаете работу, когда любое из условий перестает быть истинным, избегая Неопределенное поведение .

(3), если вы намереваетесь сохранить имя из каждого buffer, затем вам нужно выделить хранилище для каждого имени и скопировать buffer в новое хранилище до следующей итерации, или предыдущее имя будет потеряно при повторном заполнении buffer.

(4) fgetsчитает до и включает конечный '\n' в конце заполненного буфера.Вы не хотите хранить свои имена с '\n' s, свисающими с конца.strcspn - это один из самых простых и надежных способов определения количества символов в buffer перед '\n' и последующей перезаписи '\n' с помощью nul-символа .Вам не нужно ничего больше, чем показано выше, например,

        buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */

Обратитесь к strspn (3) - страница руководства Linux и посмотрите, сможете ли вы выяснить, как именно это работает.

(5) Всегда проверять возвращение при каждом открытии файла (и закрытии после записи в поток), а всегда проверять возврат каждые функция пользовательского ввода.В вашем коде нет более важного шага, чем проверка данных, которые вы получаете из файла или пользователя До вы пытаетесь обработать эти данные.В противном случае вы просто приглашаете Неопределенное поведение с небольшим нажатием клавиши или одним ошибочным написанием.

Помещение всего этого в программу, которая принимает имя файла для открытия в качестве первого аргументав программу (или читает из stdin по умолчанию, если не указан аргумент), вы можете сделать что-то вроде:

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

#define MAXNM 128   /* if you need a constant, #define one (or more) */
#define NUMNM  10   /*        ( Don't skimp on buffer size! )        */

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

    char buffer[MAXNM];
    size_t ndx = 0, name = NUMNM;
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (ndx < name && fgets (buffer, MAXNM, fp)) {
        buffer[strcspn (buffer, "\n")] = 0; /* overwrite \n with nul-char */
        fprintf (stdout, "name[%2zu] : %s\n", ndx++ + 1, buffer);
    }

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

Пример входного файла

Сейчасупражняйте вашу подпрограмму ввода с файлом, содержащим 11 имен, более чем NUMNM позволяет читать, например,

$ cat dat/namesonly.txt
Zeda'Taxu
Khano'Balme
Goni
Ryan,Elizabeth
McIntyre,Osborne
DuMond,Kristin
Larson,Lois
Thorpe,Trinity
Ruiz,Pedro
Ali,Mohammed
Vashti,Indura

Пример использования / Вывод

Чтение и остановкаNUMNM имена

$ ./bin/fgetsnames <dat/namesonly.txt
name[ 1] : Zeda'Taxu
name[ 2] : Khano'Balme
name[ 3] : Goni
name[ 4] : Ryan,Elizabeth
name[ 5] : McIntyre,Osborne
name[ 6] : DuMond,Kristin
name[ 7] : Larson,Lois
name[ 8] : Thorpe,Trinity
name[ 9] : Ruiz,Pedro
name[10] : Ali,Mohammed

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0 голосов
/ 07 июня 2019

Я вижу две причины, которые могут привести к неопределенному поведению.

Во-первых, возможен NULL в infile;Во-вторых, превышение размера буфера в одной из строк файла.Чтобы не менять большую часть своей логики, можно быстро исправить это:

FILE* infile;
char buffer[20];
infile = fopen("pathway", "r");
if (infile!=NULL) {
  for (i=-1; i < name; i++) {
     fscanf(infile, "19%s", buffer);
  }
}

Возможно, вместо этого вы можете использовать fgets.Предположим, например, следующий пример скопирован из здесь :

#include <stdio.h>

int main () {
   FILE *fp;
   char str[60];

   /* opening file for reading */
   fp = fopen("file.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   }
   if( fgets (str, 60, fp)!=NULL ) {
      /* writing content to stdout */
      puts(str);
   }
   fclose(fp);

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