Home > Net >  How to read Text Files into 2d Arrays?
How to read Text Files into 2d Arrays?

Time:11-08

Alright, I'm making a grading program/code that will have its own text file where it stores all the grades. And I thought of making a 2d array where the first "dimension" will be the student and second "dimension" the individual grade (if there's a smarter way of doing grades tell me, by the way I chose this method because it is the only way I know how I could later on just add more students or more grades) keep in mind that the number of grades and students isn't always set so there's no easy way out. Anyways I've tried something, and I think it only works with characters and not with integers (even though the grades will be 1-5).Also I want a way to print it out but I think this is the bigger problem. If I find a solution I will post it here so that if anyone else is having problems with this they can find the answer here, anyways THANKS.

    typedef char string [20];
    string row;
    int i=0,j=0;
    char arr[20][20];
    FILE *fp;
    fp=fopen("grades.txt","r");
    for(i=0;arr[i-1][j]!=EOF;i  )
    {
        fgets(row,sizeof(row),fp);//I used fgets so I could get the size of the line
        for(j=0;j<strlen(row);j  )
        {
            fscanf(fp,"%c ",&arr[i][j]);
        }
    }

I don't know if it will help but I thought the text file would look something like this:
54455
43544
22443
21232
21121

CodePudding user response:

fgets reports if it worked or not. So, reading till end of file or till the buffer is full:

for(i = 0; i < sizeof arr / sizeof *arr && fgets(arr[i], sizeof arr[i], fp); i  )
{
    // probably remove the \n that fgets writes into the buffer
    // otherwise nothing else to do
}

Site notes:

  • fgets reads from the file, no need for additional reads with fscanf
  • fgets reads a line including the newline character, remove it if you don't want it
  • you need to check if fopen worked

CodePudding user response:

I found out the best way to store grades of students in struct. Every student in general has first name, last name, grades,... You can add whatever you want. I am just fine with fname, lname, grades.

typedef struct student_s {
    char fname[25];
    char lname[25];
    int* grades;
    int count_of_grades;  // Track number of grades for each student
} student_t;

By allocating a dynamic array of student_t you can get as many students as you want.

 // Allocate array of structs
 student_t* students = (student_t *) malloc(sizeof(student_t));

By using getline() you can read the whole line from file at once (line ends with \n). getline() is not a standart C function therefore you need to put #define _GNU_SOURCE at the beginning of your script.

while ((read_len = getline(&line, &len, fp)) != -1)

Every time function getline() reads next line of file, the array size count will be incremented and reallocated array.

  count;
// Increase size of array beacause of new student to add
students = realloc(students, sizeof(student_t) * count);    
if (students == NULL)
{
    printf("Couldn't allocated memmory\n");
    return 1;
}

Next step is to allocate grades array which will store all grades of specific student. Looping through line you can extract each grade. Then by just defining members of struct you can add grades for each student.

// Allocate array to store all grades from file for one student
// Count of grades does not have to be the same for every student
students[index].grades = (int *) malloc(sizeof(int) * (read_len-1));

// Iterate grades read from file
for (int i=0; i<read_len-1;   i)
{   
    // char --> char *
    char grade[2] = "\0";
    grade[0] = line[i];

    // Add grade to the array of grades
    students[index].grades[i] = atoi(grade);
}

At the end you should store number of grades are in array for a simple manipulation with data later in your script.

// Track number of grades
students[index].count_of_grades = read_len-1;
  index

Full code:

#define _GNU_SOURCE    // necessery to use getline()
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct student_s {
    char fname[25];
    char lname[25];
    int* grades;
    int count_of_grades;
} student_t;


int main(int argc, char const *argv[])
{
    // Allocate array of structs
    student_t* students = (student_t *) malloc(sizeof(student_t));  
    int count = 0;
    int index = 0;

    FILE* fp;
    char* line = NULL;
    size_t len = 0;
    ssize_t read_len;

    fp = fopen("data.txt", "r");
    if (fp == NULL)
    {
        return 1;
    }

    // Read line by line from file until fp reaches end of file
    while ((read_len = getline(&line, &len, fp)) != -1)
    {
          count;
        // Increase size of array beacause of new student to add
        students = realloc(students, sizeof(student_t) * count);    
        if (students == NULL)
        {
            printf("Couldn't allocated memmory\n");
            return 1;
        }

        // Replace with your code, which adds name to struct or get rid of it (also from struct)
        memcpy(students[index].fname, "John", 4);
        memcpy(students[index].lname, "Wash", 4);
        
        // Allocate array to store all grades from file for one student
        // Count of grades does not have to be the same for every student
        students[index].grades = (int *) malloc(sizeof(int) * (read_len-1));

        // Iterate grades read from file
        for (int i=0; i<read_len-1;   i)
        {   
            // char --> char *
            char grade[2] = "\0";
            grade[0] = line[i];

            // Add grade to the array of grades
            students[index].grades[i] = atoi(grade);
        }

        // Track number of grades
        students[index].count_of_grades = read_len-1;
          index;
    }

    fclose(fp);
    if (line)
    {
        free(line);
    }

    // Print data from structs
    for (int i=0; i<count;   i)
    {
        printf("%s: ", students[i].fname);
        for (int j=0; j<students[i].count_of_grades;   j)
        {
            printf("%d ", students[i].grades[j]);
        }
        printf("\n");
    }

    return 0;
}
  • Related