fscanf из текстового файла в структуру указателя - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь читать из текстового файла структуру, в которой есть указатель на другую структуру.

Текстовый файл имеет следующий формат:

279288151 1 John Doe
002 1 30 04 2018
23189842 0 Jane Doe
0
282676381 1 Mark Examp
001 0 28 03 2018 03 04 2018
243897574 1 Joe Soap
003 2 14 04 2018 21 04 2018

Это мой .h файл:

#ifndef Clientes_h
#define Clientes_h

#include <stdio.h>
#include <stdlib.h>
#include "Alugueres.h"
#define ST_TAM 50


typedef struct info_cliente Cliente;

struct info_cliente{
    char nome[ST_TAM];
    long nif;
    int n_alugueres;
    int n_hist;
    pAluga aluguer;
};

typedef struct aluga Aluguer, *pAluga;
typedef struct data DataIn, *pDataIn;
typedef struct data DaraEn, *pDataEn;

struct aluga{
    int id_unico;
    int estado;
    pDataIn dataIn;
    pDataEn dataEn;
    pAluga prox;
};

struct data{
    int dia;
    int mes;
    int ano;
};

Cliente* le_fich(char *nome, int *n);

#endif /* Clientes_h */

И моя функция read_file выглядит следующим образом:

#include "Clientes.h"

Cliente* le_fich(char *nome, int *n){

    FILE *f = fopen(nome, "r");
    Cliente *aux;
    int conta = 0;

    if(!f){
        printf("Error\n");
        return NULL;
    }

    while(getc(f) != EOF){
        aux = (Cliente*)malloc(sizeof(Cliente));
        fscanf(f, "%ld %d %49[^\n]", &aux[conta].nif, &aux[conta].n_alugueres, aux[conta].nome);
        if(aux[conta].n_alugueres != 0){
            fscanf(f, "%d %d %d %d %d", &aux[conta].aluguer->id_unico, 
            &aux[conta].aluguer->estado, &aux[conta].aluguer->dataIn->dia, 
            &aux[conta].aluguer->dataIn->mes, &aux[conta].aluguer->dataIn->ano);
        }
        conta++;
    }
return aux;
}

Это выдает ошибку bad_access при попытке запустить fscanf после успешного выполнения if (при обращении к указателю структуры для моей даты). Если бы кто-нибудь мог мне помочь, был бы очень признателен.

Ответы [ 3 ]

0 голосов
/ 30 апреля 2018

Вы используете и getc и fscanf для доступа к файлу.

Если вы хотите использовать fscanf, вы не должны использовать getc.

Используйте возвращаемое значение fscanf, чтобы сообщить, когда файл закончился. fscanf вернет количество совпадений. В вашем случае, в случае успеха, он должен вернуть 3.

int ret;
do{
    aux = (Cliente*)malloc(sizeof(Cliente));
    ret = fscanf(f, "%ld %d %49[^\n]", &aux[conta].nif, &aux[conta].n_alugueres, aux[conta].nome);
    if((ret ==3) && (aux[conta].n_alugueres != 0)){
        fscanf(f, "%d %d %d %d %d", &aux[conta].aluguer->id_unico, 
        &aux[conta].aluguer->estado, &aux[conta].aluguer->dataIn->dia, 
        &aux[conta].aluguer->dataIn->mes, &aux[conta].aluguer->dataIn->ano);
    }
    conta++;
}while (ret == 3);
0 голосов
/ 30 апреля 2018

Выдает ошибку bad_access при попытке запустить fscanf после успешного выполнения if

2 задачи:

  1. Как указано @ Rishikesh Raje , @ Cyclonecode , распределение подходит только для aux = aux[0], а также для других пропущенных выделений.

  2. Обычное подозрение на проблемы со сканированием заключается в том, что fscanf() не сканировал то, что ожидалось, и в коде не было проверок возвращаемого значения. (Подсказка: когда строка только "0\n", 2-е fscanf() читает больше, чем ожидалось в OP).

    ret = fscanf(f, "%ld %d %49[^\n]", ...);
    if((ret ==3) && (aux[conta].n_alugueres != 0)){
        fscanf(f, "%d %d %d %d %d", ...
        // code errantly does not check the return value of `fscanf()`.
    }
    else {
      break; // This code missing, what to do when `ret != 3`
    }
    

Простое решение обеих проблем: перераспределение по мере необходимости и проверка успешности чтения 2 строк и их сканирования.

Я рекомендую не выделять данные для новой пары строк, пока входные данные не будут проверены.

Cliente *aux = NULL; // Initialize to NULL
size_t n = 0;    // Keep count of record count
char buf1[150];  // Use generous buffers.  Suggest 2x maximum expected need
char buf2[100];

// while 2 lines successfully read
while (fgets(buf1, sizeof buf1, f) && fgets(buf2, sizeof buf2, f)) {
  // Form objects to be scanned into with default values.
  struct info_cliente cli = { 0 };
  struct aluga alu = { 0 };
  struct data dat = { 0 };

  if (sscanf(buf1, "%ld %d %49[^\n]", &cli.nif, &cli.n_alugueres, cli.nome) != 3) {
    perror("Unexpected 1st line");
    break;
  }
  if (cli.n_alugueres == 0) {
    if (sscanf(buf2, "%d", &alu.id_unico) != 1 || alu.id_unico != 0)) {
      perror("Unexpected 2nd line 0");
      break;
    }
  }
  else if (cli.n_alugueres == 1) {
    if (sscanf(buf2, "%d %d %d %d %d", &alu.id_unico, &alu.estado, &dat.dia,
        &dat.mes, &dat.ano) != 5) {
      perror("Unexpected 2nd line");
      break;
    }
    alu.dataIn = malloc(sizeof *alu.dataIn);
    *alu.dataIn = dat;
    cli.aluguer = malloc(sizeof *cli.aluguer);
    *cli.aluguer = alu;
  } else {
    perror("Unexpected 2nd line n_alugueres");
    break;
  }
  Cliente *tmp = realloc(aux, sizeof *aux * (n+1));
  aux = tmp;
  aux[n] = cli;
  n++;
}

Cliente *tmp = realloc(aux, sizeof *aux * (n+1));
aux = tmp;
aux[n] = NULL;  // NULL terminate the list

Примечание Ошибка проверки malloc() / realloc() опущена для краткости в приведенном выше примере кода.

0 голосов
/ 30 апреля 2018

Прямо сейчас вы выделяете память для aux в цикле, а затем пытаетесь получить доступ к элементу, используя индекс, который не будет работать. Вместо этого вам нужно выделить память для всех Cliente записей. Если вы знаете количество записей в файле, вы можете просто сделать aux = (Cliente*)malloc(size * sizeof(Cliente));. Вы также можете проверить, как вы можете использовать realloc() в реальном цикле.

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