Several issues with the Question code...
1) Definition of main():
int main(int argc, char* argv[])
It must return an integer. Add a return statement at the end of main(), and make a proper "CLEANUP" section:
printData(student, count);
CLEANUP:
if(in_file)
fclose(in_file);
return(0);
}
2) Better handling of fopen() error condition:
if(( in_file = fopen(argv[1], "r")) == NULL)
{
printf("unable to open the file");
goto CLEANUP;
}
And, initialize the in_file pointer:
int main(int argc, char* argv[])
{
FILE *in_file = NULL;
3) Next, the exact definition of student needs to be established. Is it a static array, or is a pointer to a dynamically allocated array? I will assume that you would like to use a dynamic array (given the question text). However, this assumption conflicts with the following line, which defines student as a static array:
struct people student[20];
Change it to:
struct people *student = NULL;
4) Now, the following question code allocates a new (separate) chunk of memory for each student:
student = malloc(sizeof(struct people));
However, what is needed is all the student records in one array, in the same chunk of memory. So, what is needed is to expand a chunk of memory to include student records as they are read, like this:
while (fgets(buffer, sizeof(buffer), in_file))
{
void *tmp = realloc(student, sizeof(struct people) * (count + 1));
if(NULL == tmp)
{
printf("realloc() failed.\n");
goto CLEANUP;
}
student = tmp;
token = strtok(buffer, del);
5) Take a look at the people structure:
struct people
{
char* name[10];
char* courseID[15];
int grade;
};
It appears that the question code has some difficulty when it comes to pointers & arrays. The code is attempting to define the name and courseID fields as both pointers, and arrays. Given that the question is to do with dynamically allocating stuff, I elect to go that direction. Hence, this structure should be changed to the following:
struct people
{
char *name;
char *courseID;
int grade;
};
6) So, each time through the loop, the student name will be placed in allocated storage, and pointed to by the .name field. So, change this:
token = strtok(buffer, del);
strcpy(student[count]->name, token);
count++;
}
to this:
token = strtok(buffer, del);
student[count].name = strdup(token);
count++;
}
7) I don't understand the intent of this line:
if (strcmp((student[i].name, student[i].courseID) > 0))
I am inclined to eliminate it.
8) The following line has flaws:
printf("%s %s", student[i].name, student[i].grade)
Change it to this to print the integer grade (and don't forget the ending semicolon):
printf("%s %d\n", student[i].name, student[i].grade);
The '\n' makes the output look better, one record per line.
9) Since student is a pointer to dynamically allocated memory (not a static array), change this:
void printData(struct people student[], int count)
to this:
void printData(struct people *student, int count)
10) Now, finish the task of parsing the data; from this:
token = strtok(buffer, del);
strcpy(student[count].name, token);
count++;
}
to this:
token = strtok(buffer, del);
student[count].name = strdup(token);
token = strtok(NULL, del);
student[count].courseID = strdup(token);
token = strtok(NULL, del);
student[count].grade = strtol(token, NULL, 10);
count++;
}
11) Now, to make life easier, sort the array. First by courseID, then by name:
...
count++;
}
/** Sort the array by coursID, then by name. **/
qsort(student, count, sizeof(*student), CmpStudentRecs);
printData(student, count);
...
Which will require an additional "Compare Student Recs" function:
int CmpStudentRecs(const void *recA, const void *recB)
{
int result = 0;
struct people *stuRecA = (struct people *)recA;
struct people *stuRecB = (struct people *)recB;
/** First compare the courseIDs **/
result=strcmp(stuRecA->courseID, stuRecB->courseID);
/** Second (if courseIDs match) compare the names **/
if(!result)
result=strcmp(stuRecA->name, stuRecB->name);
return(result);
}
12) Some finishing touches with the printData() function:
void printData(struct people *student, int count)
{
int i;
char *courseID = "";
for(i=0; i<count; i++)
{
if(strcmp(courseID, student[i].courseID))
{
printf("%s\n", student[i].courseID);
courseID = student[i].courseID;
}
printf("\t%s %d\n", student[i].name, student[i].grade);
}
}
Finished. Output:
SLES11SP2:~/SO> ./test data.txt
MATH 1324
David 90
John 90
Omondi 89
SCI 1401
David 88
SLES11SP2:~/SO>
SPOILER
struct student? 'student = malloc(sizeof(struct student))' Did you meanstudent = malloc(sizeof(struct people))?if (strcmp((student[i].name, student[i].courseID) > 0))What is the intent?