'C Problems with fscanf

Thanks for all the answers, after the corrections the code did not work for a stupid error ... I opened both files with the same file pointer "database" ...

I've read dozens of questions like this but I can't get out of it, I'm going crazy. The exercise that I have to do asks me to organize the items of a list in a file .txt that has elements of the type: Name Surname Age Wage, in alphabetical order according to the surname. I have already created a function to insert the elements into the file and it works well. I then went to the function to organize them but the process stops after the fscanf, and putting some test printf I saw that no values are assigned to the strings or that are assigned absurd numbers. Please help ... thanks.

This is the code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 64
#define MAXFILE 100

void insert();
int fullcheck();
void sort();

typedef struct {
    char name[MAX];
    char surname[MAX];
    int age;
    double wage;
} data;

int main() {
    insert();
    return EXIT_SUCCESS;
}

void insert() {
    char c;
    int i;
    data tmp;
    FILE* database;
    if ((fullcheck())>MAXFILE-1)
        printf("Errore: database pieno.\n");
    else {
        database=fopen("database.txt", "a");
        printf("Nome: ");
        fgets(tmp.name, MAX, stdin);
        tmp.name[strlen(tmp.name)-1]='\0';
        printf("Cognome: ");
        fgets(tmp.surname, MAX, stdin);
        tmp.surname[strlen(tmp.surname)-1]='\0';
        for (i=0; i<strlen(tmp.surname); i++) {
            if (tmp.surname[i]==' ')
                tmp.surname[i]='#';
        }
        printf("Eta': ");
        scanf("%d", &tmp.age);
        printf("Salario: ");
        scanf("%lf", &tmp.wage);
        while((c=getchar())!='\n');
        fprintf(database, "%s %s %d %.0lf \n", tmp.name, tmp.surname, tmp.age, tmp.wage);
        fflush(database); fclose(database);
        if ((fullcheck())>1)
            sort();
    }
}

int fullcheck() {
    char c;
    int r=0;
    FILE* database;
    if ((database=fopen("database.txt", "r"))==NULL) {
        return 0;
    }
    else {
        while((c=getc(database))!=EOF) {
            if(c=='\n')
                r++;
        }
        return r;
    }
}

void sort() {
    char tmpstr[MAX];
    int len=fullcheck(), i, a, b;
    data tmp[len];
    FILE* database;
    FILE* sorted;
    database=fopen("database.txt", "r");
    database=fopen("sorted.txt", "w");
    for (i=0; i<=len; i++) {
        fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
    }
    for (a=0 ; a<(len-1); a++) {
        for (b=0; b<(len-1); b++) {
            if ((tolower(tmp[b].surname[0]))>(tolower(tmp[b+1].surname[0]))) {
                strcpy(tmpstr, tmp[b].surname);
                strcpy(tmp[b].surname, tmp[b+1].surname);
                strcpy(tmp[b+1].surname, tmpstr);
            }
        }
    }
    for (a=0; a<(len-1); a++) {
        fprintf(sorted, "%s %s %d %.0lf \n", tmp[a].name, tmp[a].surname, tmp[a].age, tmp[a].wage);
    }
    fflush(database); fclose(database); remove("database.txt");
    fflush(sorted); fclose(sorted); rename("sorted.txt", "database.txt");
} 
c


Solution 1:[1]

Off by 1

Code attempts to read into len+1 elements of tmp[].

data tmp[len];
for (i=0; i<=len; i++) {  // too many
    fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
}

I saw that no values are assigned to the strings (OP)

Better code would use width limits and test fscanf() result before using the data scanned.

//         v---- < not <=
for (i=0; i<len; i++) { 
    if (fscanf(database, "%63s %63s %d %lf",  
        &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage) != 4) {
        //                                                        ^^^^ test!
      break;
    }

Even better code would read a line with fgets() into a stirng and then attempt to parse the string.

Off by 2

Code's attempt to find number of lines can be short by 1 if the last line does not end with a '\n'.

Alternative

size_t fullcheck(void) {
    FILE* database = fopen("database.txt", "r");
    if (database == NULL) {
        return 0;
    }
    int previous = '\n';
    int c;
    size_t r=0;
    while((c=getc(database))!=EOF) {
      if (previous == '\n') r++;
      previous = c;
    }
    fclose(database);
    return r;
}

Missing fclose()

fullcheck() doesn't close the file after opening it.

int

Use an int to distinguish the typically 257 different returns values of fgetc(). Note when char` is unsinged, OP's code is an infinite loop.

More woes

The loop to print the sorted list is off-by-one, too short. And the sorting itself only looks at the first letter of each name, should use strcmp. @user3386109

Maybe more?

Solution 2:[2]

Make sure to close the file here, before every return:

int fullcheck() {
    char c;
    int r=0;
    FILE* database;
    if ((database=fopen("database.txt", "r"))==NULL) {
        fclose(database);
        return 0;
    }
    else {
        while((c=getc(database))!=EOF) {
            if(c=='\n')
                r++;
        }
        fclose(database);
        return r;
    }
}

And also a little bit fixing in the loop_counters here:

void sort() {
    char tmpstr[MAX];
    int len=fullcheck(), i, a, b;
    data tmp[len];
    FILE* database;
    FILE* sorted;
    database=fopen("database.txt", "r");
    sorted=fopen("sorted.txt", "w+");
    for (i=0; i<len; i++) {
        fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
        printf("%s", tmp[b+1].surname);
                system("pause");
    }
    for (a=0 ; a<(len); a++) {
        for (b=0; b<(len); b++) {
            if ((tolower(tmp[b].surname[0]))>(tolower(tmp[b+1].surname[0]))) {
                strcpy(tmpstr, tmp[b].surname);
                strcpy(tmp[b].surname, tmp[b+1].surname);
                strcpy(tmp[b+1].surname, tmpstr);
                printf("%s", tmp[b+1].surname);
                system("pause");
            }
        }
    }
    for (a=0; a<(len); a++) {
        fprintf(sorted, "%s %s %d %.0lf \n", tmp[a].name, tmp[a].surname, tmp[a].age, tmp[a].wage);
    }
    fclose(sorted); 
    fclose(database); 
} 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Dima Belemezov