cfwrite

Writing struct into .txt file in C


I'm trying to read the data from .txt file into struct array and then writing some of this data into another .txt file using said array.

My code:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 5 // max array size
//C:\\Users\\PATOX\\Desktop\\uczniowie.txt
 struct para
{
    char name[15];
    int grade;
};

int read(FILE* file, struct para tab[], int m,  int *k) {
    FILE* output;
    char path[80];
    printf("Enter input file path: ");
    scanf_s("%s", path, 80);
    file = fopen(path, "r");
    if (file == NULL)
    {
        printf("\nError opening input file\n");
        return 1;
    }
    else
    {
        char path[80];
        printf("Enter output file path: ");
        scanf_s("%s", path, 80);
        output = fopen(path, "w");
        if (output == NULL)
        {
            printf("\nError opening output file\n");
            return 1;
        }
        for (int i = 0; i < m; i++)
        {
            if (!feof(file))
            {
                int index;
                char name[15];
                int grade;
                fscanf(file, "%d %s %d", &index, name, &grade);
                strcpy(tab[i].name, name);
                tab[i].grade = grade;
                fwrite(&(tab[i]), sizeof(struct para), 1, output);
                (*k)++;
            }
        }
    }
    fclose(file);
    fclose(output);
    return 0;
}



void print_array(struct para tab[], int m) {
    for (int i = 0; i < m; i++)
    {
        printf("%s %d\n", tab[i].name, tab[i].grade);
    }

}


int main() {
    int k = 0;                  //data counter
    FILE* file;
    struct para tab[5];
    read(&file, tab, MAX, &k);
    print_array(tab, k);
    return 0;
}

When I check the output .txt file the data is here, however only .name is written as expected, the second item is written as some artifact:

Expected (output.txt)

Drozd 4   Jas 5   Tom 6   Bas 8   

Actual (output.txt) (output.txt)

Drozd ÌÌÌÌÌÌÌÌÌÌ   Jas ÌÌÌÌÌÌÌÌÌÌÌÌ   Tom ÌÌÌÌÌÌÌÌÌÌÌÌ   Bas ÌÌÌÌÌÌÌÌÌÌÌÌ   

Solution

  • In trying out your program experimenting with various methods of pushing the structure data to a text output file, I could not successfully produce an output data file file with just text data. My experience with outputting structures to a file, the file is usually defined as a binary file rather than a text file.

    With that in mind, I did a bit of refactoring of your program to output the data as text data. Following is a listing of the refactored code.

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #define MAX 20 // max array size
    //C:\\Users\\PATOX\\Desktop\\uczniowie.txt
    struct para
    {
        char name[15];
        int grade;
    };
    
    int readx(FILE* filex, struct para tab[], int m,  int *k)
    {
        FILE* output;
        char path[80];
        int check = 0;
        printf("Enter input file path: ");
        check = scanf("%s", path);
        filex = fopen(path, "r");
        if (filex == NULL)
        {
            printf("\nError opening input file\n");
            return 1;
        }
        else
        {
            char path[80];
            printf("Enter output file path: ");
            check = scanf("%s", path);
            output = fopen(path, "w");
            if (output == NULL)
            {
                printf("\nError opening output file\n");
                return 1;
            }
            for (int i = 0; i < m; i++)
            {
                if (!feof(filex))
                {
                    int index;
                    char name[15];
                    int grade;
                    check = fscanf(filex, "%d %s %d", &index, name, &grade);
    
                    if (check < 0)  /* Exit loop if no more data is found */
                    {
                        break;
                    }
    
                    strcpy(tab[i].name, name);
                    tab[i].grade = grade;
                    /* fwrite(&(tab[i]), sizeof(struct para), 1, output); */
                    /* Use fprintf instead for text type output */
                    fprintf(output, "%s %d\n", name, grade);
                    (*k)++;
                }
            }
        }
        fclose(filex);
        fclose(output);
        return 0;
    }
    
    void print_array(struct para tab[], int m)
    {
        for (int i = 0; i < m; i++)
        {
            printf("%s %d\n", tab[i].name, tab[i].grade);
        }
    }
    
    int main()
    {
        int k = 0;                  //data counter
        FILE* filex = NULL;
        struct para tab[MAX];       /* Sized for maximum allowable structure size */
        readx(filex, tab, MAX, &k);
        print_array(tab, k);
        return 0;
    }
    

    Following are some items to note.

    With that, the following file set was built for testing.

    Grade Data

    Following was the sample grade data.

    1   Craig   88
    2   Kelly   92
    3   Kurt    78
    4   Lisa    94
    5   Benjamin    89
    6   Troy    91
    7   Isaac   97
    8   William 78
    9   Elsie   85
    10  Winston 75
    

    Following is sample terminal output testing this refactored code.

    @Vera:~/C_Programs/Console/TextWrite/bin/Release$ ./TextWrite 
    Enter input file path: Sample.txt
    Enter output file path: Grades.txt
    Craig 88
    Kelly 92
    Kurt 78
    Lisa 94
    Benjamin 89
    Troy 91
    Isaac 97
    William 78
    Elsie 85
    Winston 75
    

    Following is the text data that was placed into file "Grades.txt"

    Craig 88
    Kelly 92
    Kurt 78
    Lisa 94
    Benjamin 89
    Troy 91
    Isaac 97
    William 78
    Elsie 85
    Winston 75
    

    So, to reiterate, if the output data should be in a textual format, probably the "fprintf" function would be used; otherwise, if the program truly needs to store each structure as a record, the program would want to utilize an output file defined as a binary file.

    Hopefully, this refactored code meets the spirit of your project.