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 withfscanf
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;
}