I have got a function to read a file and attribute to a struct array multiple ints and strings, my fscanf
format string looks like this: "%d.%d.%d.%d %d %60c%60c%d %8c"
.
And everything is OK if while I scan it and if I use a printf, but if I don't then the 2 last strings become corrupted at the end.
Since the file is gigantic and that is not the purpose of the function, I would like to take that printf out.
typedef struct
{
int nacional;
int regional;
int distrital;
int municipal;
}id_geo;
typedef struct
{
id_geo id_geo;
long int cartao_cid;
char nome_dono[61];
char morada[61];
int num_porta;
char codigo_postal[9];
}prop_id_dono;
prop_id_dono *ler_ficheiro(char *file_name, int num_linha) {
prop_id_dono *info_geral;
long int cartao_cid;
char nome_ficheiro;
char nome_dono[60];
char morada[60];
int num_porta;
char codigo_postal[8];
int nacional;
int regional;
int distrital;
int municipal;
int i = 0;
FILE *fp;
fp = fopen(file_name, "r");
if (fp == NULL)
printf("Peço desculpa, mas não foi possível abrir o ficheiro.");
info_geral = (prop_id_dono *)malloc(sizeof(prop_id_dono) * num_linhas);
while (fscanf(fp, "%d.%d.%d.%d %ld %60c%60c%d %8c\n",
&nacional, ®ional, &distrital, &municipal,
&cartao_cid, nome_dono, morada, &num_porta, codigo_postal) != EOF) {
// Faz o scan ao ficheiro através de variáveis temporais, sendo que só
// depois é que atribui valores ao vetor que contém a informação geral
info_geral[i].id_geo.nacional = nacional;
info_geral[i].id_geo.regional = regional;
info_geral[i].id_geo.distrital = distrital;
info_geral[i].id_geo.municipal = municipal;
info_geral[i].cartao_cid = cartao_cid;
strcpy(info_geral[i].nome_dono, nome_dono + '\0');
strcpy(info_geral[i].morada, morada + '\0');
info_geral[i].num_porta = num_porta;
strcpy(info_geral[i].codigo_postal, codigo_postal + '\0');
//This is the magical printf
printf("%d.%d.%d.%d %ld %s%s%d %s \n",
info_geral[i].id_geo.nacional, info_geral[i].id_geo.regional,
info_geral[i].id_geo.distrital, info_geral[i].id_geo.municipal,
info_geral[i].cartao_cid, info_geral[i].nome_dono,
info_geral[i].morada, info_geral[i].num_porta,
info_geral[i].codigo_postal);
i++;
}
fclose(fp);
return info_geral;
}
The input is something like this, but it repeats 20,000 something times in the file 1.1.1.1 1234568 Name, 60 caracters in total(including the spaces)Adress(same thing with the spaces here)House Number Postal Code
You parse input fragments with %60c
into character arrays of size 60
.
Assuming the conversion succeeds, these arrays will not contain proper C strings, and your attempt at concatenating a '\0'
does not work in C.
Here are ways to improve your program:
sscanf()
fo parsing.prop_id_dono
structure should be made large enough too.sscanf
and report conversion failuresnum_linhas
lines.Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int nacional;
int regional;
int distrital;
int municipal;
} id_geo;
typedef struct {
id_geo id_geo;
long int cartao_cid;
char nome_dono[61];
char morada[61];
int num_porta;
char codigo_postal[9];
} prop_id_dono;
prop_id_dono *ler_ficheiro(const char *file_name, int num_linha) {
char buf[256];
prop_id_dono *info_geral;
long int cartao_cid;
char nome_ficheiro;
char nome_dono[61];
char morada[61];
int num_porta;
char codigo_postal[9];
int nacional;
int regional;
int distrital;
int municipal;
int i = 0;
FILE *fp;
fp = fopen(file_name, "r");
if (fp == NULL) {
printf("Peço desculpa, mas não foi possível abrir o ficheiro.");
return NULL;
}
// use calloc to allocate an array initialized to all bits zero
info_geral = (prop_id_dono *)calloc(num_linhas, sizeof(prop_id_dono));
if (info_geral == NULL) {
fclose(fp);
return NULL;
}
while (i < num_linhas && fgets(buf, sizeof buf, fp) != NULL) {
// Faz o scan ao ficheiro através de variáveis temporais, sendo que só
// depois é que atribui valores ao vetor que contém a informação geral
if (sscanf(buf, "%d.%d.%d.%d %ld %60c%60c%d %8c",
&nacional, ®ional, &distrital, &municipal,
&cartao_cid, nome_dono, morada, &num_porta, codigo_postal) != 9) {
printf("parsing error: %s", buf);
continue;
}
info_geral[i].id_geo.nacional = nacional;
info_geral[i].id_geo.regional = regional;
info_geral[i].id_geo.distrital = distrital;
info_geral[i].id_geo.municipal = municipal;
info_geral[i].cartao_cid = cartao_cid;
nome_dono[60] = '\0';
strcpy(info_geral[i].nome_dono, nome_dono);
morada[60] = '\0';
strcpy(info_geral[i].morada, morada);
info_geral[i].num_porta = num_porta;
codigo_postal[8] = '\0';
strcpy(info_geral[i].codigo_postal, codigo_postal);
i++;
}
fclose(fp);
// note that the caller does not receive the number of lines parsed.
// passing the address of a int for this purpose if a good solution.
return info_geral;
}