Search code examples
cfilestructdynamic-arrays

Reading a file in a table format and print it


So, what I'm trying to do is, at first create a file in a table format then read that file and put that file in 4 different dynamic arrays using struct and print them in order

So, here is the struct I'm using: I used capacity = 5 to change the size of dynamic array later but still don't know how to change it

struct score{
    char *str1;
    char *str2;
    int *num1;
    int *num2;
};

int main(){
    int capacity = 5;
    struct score table;
    table.str1=(char *)malloc(sizeof(int)*capacity);
    table.str2=(char *)malloc(sizeof(int)*capacity);
    table.num1=(int *)malloc(sizeof(int)*capacity);
    table.num2=(int *)malloc(sizeof(int)*capacity);

After I created a File to write:

    inFile = fopen("Subject.txt", "w");
    if(inFile == NULL)
    {
      printf("Error!");   
      exit(1);             
    }

    char names[] = {"Joe Math 52 85\nBilly Phy 65 70\nSophia Chem 86 71"};

    fprintf(inFile,"%s",names);
    fclose(inFile);

At the end reading a File and putting them in arrays:

    inFile = fopen("Subject.txt", "r");
    if(inFile == NULL)
    {
      printf("Error!");   
      exit(1);             
    }
    fscanf(inFile, "%s %s %d %d",table.str1, table.str2, table.num1, table.num2);
    fclose(inFile);

    for(i=0;i<6;i++){
        printf("%s %s %d %d\n",table.str1, table.str2, table.num1, table.num2);
    }

So, I need this code to print like this, and I couldn't do it:

Name   Subj.  Test1  Test2
------------------------
Joe    Math   52     85
Billy  Phy    65     70
Sophia Chem   86     71

Here is my full Code just in case:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct score{
    char *str1;
    char *str2;
    int *num1;
    int *num2;
};

int main(){
    FILE *inFile;
    int num, capacity = 5, i;
    struct score table;
    table.str1=(char *)malloc(sizeof(int)*capacity);
    table.str2=(char *)malloc(sizeof(int)*capacity);
    table.num1=(int *)malloc(sizeof(int)*capacity);
    table.num2=(int *)malloc(sizeof(int)*capacity);
    inFile = fopen("Subject.txt", "w");
    if(inFile == NULL)
    {
      printf("Error!");   
      exit(1);             
    }

    char names[] = {"Joe Math 52 85\nBilly Phy 65 70\nSophia Chem 86 71"};

    fprintf(inFile,"%s",names);
    fclose(inFile);

    inFile = fopen("Subject.txt", "r");
    if(inFile == NULL)
    {
      printf("Error!");   
      exit(1);             
    }
    fscanf(inFile, "%s %s %d %d",table.str1, table.str2, table.num1, table.num2);
    fclose(inFile);

    for(i=0;i<6;i++){
        printf("%s %s %d %d\n",table.str1, table.str2, table.num1, table.num2);
    }
}

Solution

  • You want an array of structs.

    But, you've got a fixed number of scores (e.g. num1, num2). This, also, should be an array.

    I think you'll be better off with a second struct. That is, struct student and struct score

    And, Paul outlined how to do this with fixed limits.

    In general, you could allocate things dynamically to accomodate an arbitrary number of students that have an arbitrary (and varying) number of test scores.

    Based on your sample data, your input format is:

    <name> <subject> <score1> <score2> ... <scoreN>
    

    Because of this, I interpret the subject to be the students major, so it gets grouped in the student record.

    Otherwise, we'd need something like:

    <name> <subject1> <score1> <subject2> <score2> ... <subjectN> <scoreN>
    

    And, then, the subject would go into the score record


    To get it to work, I had to [heavily] refactor your code:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    struct score {
        int score;
    };
    
    struct student {
        char *name;
        char *subject;
        struct score *scores;
        int count;
    };
    
    int
    main(void)
    {
        FILE *inFile;
        struct student *students = NULL;
        int student_count = 0;
        struct student *who;
        struct score *score;
        const char *delim = " \t\n";
        char *cp;
        char buf[1000];
    
        inFile = fopen("Subject.txt", "w");
        if (inFile == NULL) {
            printf("Error!");
            exit(1);
        }
    
        char names[] = { "Joe Math 52 85\nBilly Phy 65 70\nSophia Chem 86 71" };
    
        fprintf(inFile, "%s", names);
        fclose(inFile);
    
        inFile = fopen("Subject.txt", "r");
        if (inFile == NULL) {
            printf("Error!");
            exit(1);
        }
    
        while (1) {
            // get a line
            cp = fgets(buf,sizeof(buf),inFile);
            if (cp == NULL)
                break;
    
            // get the student name
            cp = strtok(buf,delim);
            if (cp == NULL)
                continue;
    
            // allocate new student record
            students = realloc(students,
                sizeof(struct student) * (student_count + 1));
            who = &students[student_count];
            student_count += 1;
    
            // save the student name
            who->name = strdup(cp);
    
            // get the subject and save it
            cp = strtok(NULL,delim);
            if (cp == NULL)
                break;
            who->subject = strdup(cp);
    
            // clear out the scores array
            who->count = 0;
            who->scores = NULL;
    
            // get all scores
            while (1) {
                cp = strtok(NULL,delim);
                if (cp == NULL)
                    break;
    
                // increase the size of the scores array for this student
                who->scores = realloc(who->scores,
                    sizeof(struct score) * (who->count + 1));
                score = &who->scores[who->count];
                who->count += 1;
    
                score->score = atoi(cp);
            }
        }
    
        fclose(inFile);
    
        for (who = &students[0];  who < &students[student_count];  ++who) {
            printf("%10s %10s", who->name, who->subject);
    
            for (score = who->scores;  score < &who->scores[who->count];  ++score)
                printf("%4d",score->score);
    
            printf("\n");
        }
    
        return 0;
    }
    

    Here's the program output:

           Joe       Math  52  85
         Billy        Phy  65  70
        Sophia       Chem  86  71