fscanf从文本文件到结构指针

时间:2018-04-30 11:44:37

标签: c pointers struct

我试图从文本文件读取到具有指向另一个结构的指针的结构。

文本文件格式如下:

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;
}

在if成功后(当访问我日期的struct的指针时)尝试运行fscanf时,它给出了一个bad_access错误。如果有人能帮助我,我会非常感激。

3 个答案:

答案 0 :(得分:1)

现在你在循环中为aux分配内存,然后尝试使用不起作用的索引来访问元素。相反,您需要为所有Cliente条记录分配内存。如果您知道文件中的记录数,则可以执行aux = (Cliente*)malloc(size * sizeof(Cliente));。您还可以检查如何在实际循环中使用realloc()

答案 1 :(得分:1)

  

fscanf成功后尝试运行if时,我发现了bad_access错误

2个问题:

  1. 正如@Rishikesh Raje @Cyclonecode所指出的,分配仅适用于aux = aux[0]以及其他缺失的分配。

  2. 扫描问题的常见疑问是fscanf()没有扫描预期的内容,代码缺少对返回值的检查。 (提示:当行仅为"0\n"时,第二个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`
    }
    
  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()的错误检查。

答案 2 :(得分:0)

您正在使用 <{strong> getcfscanf来访问该文件。

如果您想使用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);