在动态分配内存的同时将文件数据读取到结构数组

时间:2021-07-22 15:46:01

I need help solving the code below. After the code is compiled using gcc it can be run like ./compiledFile inputFile.txt It should take the inputFile.txt read it while allocating memory dynamically for each variable in this case name and courseID, but my code is not working. The place that I don't understand the most and need help is allocating memory, inserting data into structures and printing the data like the example given below. By the look of this code you could tell that I am a newbie to c and dynamic memory allocation and structure in all.

我需要帮助解决下面的代码。在使用gcc编译代码之后,它可以像./compiledFile一样运行inputFile.txt它应该采取inputFile.txt读取它,同时动态地为每个变量分配内存,在这种情况下name和courseID,但我的代码不起作用。我不太了解并需要帮助的地方是分配内存,将数据插入结构并打印数据,如下面给出的示例。通过这段代码你可以看出我是c和动态内存分配和结构的新手。

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

struct people
{
  char* name[10];
  char* courseID[15];
  int grade;
};

void printData(struct people student[], int count);
int main(int argc, char* argv[])
{
  FILE *in_file;
  char buffer[30];
  char *token, *del=",";
  int count=0;

  struct people student[20];

  if(( in_file = fopen(argv[1], "r")) == NULL)
  {
     printf("unable to open the file");
  }
  while (fgets(buffer, sizeof(buffer), in_file))
  {
     student = malloc(sizeof(struct people));
     token = strtok(buffer, del);
     strcpy(student[count].name, token);
     count++;
  }
  fclose(in_file);
  printData(student, count);
}
void printData(struct people student[], int count)
{
  int i;
  for(i=0; i<count; i++)
  {
    printf("%s", student[i].courseID);
    if (strcmp((student[i].name, student[i].courseID) > 0))
    {
      printf("%s  %s", student[i].name, student[i].grade)
    }
  }
}

the data.txt file has the following content separated by a comman:

data.txt文件具有由comman分隔的以下内容:

John,MATH 1324,90 David,SCI 1401,88 Omondi,MATH 1324,89 David,MATH 1324,90

John,MATH 1324,90 David,SCI 1401,88 Omondi,MATH 1324,89 David,MATH 1324,90

when printed out it should look like the following:

打印出来时,它应如下所示:

MATH 1324
John 90
Omondi 89
David 90

SCI 1401
David 88

4 个解决方案

#1


0  

  1. Change the definition of people to:

    将人员的定义更改为:

    struct people
    {
      char name[10];
      char courseID[15];
      int grade;
    };
    

    This assumes that name won't be longer than 9 characters and coursID won't be longer than 14 characters. If that is not true, change them accordingly.

    这假设名称不会超过9个字符,而coursID不会超过14个字符。如果不是这样,请相应地更改它们。

  2. The line:

    student = malloc(sizeof(struct student);
    

    is wrong in couple of ways.

    在某些方面是错误的。

    • student is already declared to be an array of people. You cannot assign it to point to memory allocated by malloc.

      学生已被宣布为一群人。您不能将其指定为指向malloc分配的内存。

    • struct student is not a type.

      struct student不是一种类型。

    That line can be removed.

    该行可以删除。

  3. The line

    strcpy(student[count].name, token);
    

    can cause problems if the length of token is longer than 10 (or whatever size you choose for name in people). The safer thing to do is use strncpy.

    如果令牌的长度超过10(或您为人名选择的任何大小),可能会导致问题。更安全的事情是使用strncpy。

    strncpy(student[count].name, token, 10);
    student[count].name[9] = '\0';
    
  4. You have not set the value of courseID anywhere. Yet, you are trying to print it in printData. You are doing the same thing for grade. You need to update the processing of input lines to set those correctly.

    您没有在任何地方设置courseID的值。但是,您正尝试在printData中打印它。你正在为年级做同样的事情。您需要更新输入行的处理以正确设置它们。

    Change the while loop to:

    将while循环更改为:

    while (fgets(buffer, sizeof(buffer), in_file))
    {
       token = strtok(buffer, del);
       strncpy(student[count].name, token, 10);
       student[count].name[9] = '\0';
       token = strtok(NULL, del);
       strncpy(student[count].courseID, token, 15);
       student[count].courseID[14] = '\0';
       token = strtok(NULL, del);
       student[count].grade = atoi(token);
       count++;
    }
    
  5. There are couple of syntax errors in printData. However, fixing those syntax errors does not take care of your printing requirements. It will be easier to print the data in the order that you want to if you sort the data. The following functions will help you sort the data.

    printData中有几个语法错误。但是,修复这些语法错误并不会影响您的打印要求。如果对数据进行排序,将按照您希望的顺序打印数据会更容易。以下功能将帮助您对数据进行排序。

    int compareStudent(const void* ptr1, const void* ptr2)
    {
       struct people* p1 = (struct people*)ptr1;
       struct people* p2 = (struct people*)ptr2;
       return (strcmp(p1->courseID, p2->courseID));
    }
    
    void sortData(struct people student[], int count)
    {
       qsort(student, count, sizeof(struct people), compareStudent);
    }
    

    You can call sortData before calling printData or call sortData first in printData. The logic for printing the data needs to be updated a little bit. Here's an updated printData.

    您可以在调用printData之前调用sortData,或者先在printData中调用sortData。打印数据的逻辑需要稍微更新一下。这是一个更新的printData。

    void printData(struct people student[], int count)
    {
      int i;
      int j;
    
      sortData(student, count);
    
      for(i=0; i<count; ++i)
      {
        printf("%s\n", student[i].courseID);
        printf("%s %d\n", student[i].name, student[i].grade);
        for ( j = i+1; j < count; ++j )
        {
           if (strcmp(student[i].courseID, student[j].courseID) == 0)
           {
              printf("%s %d\n", student[j].name, student[j].grade);
           }
           else
           {
              i = j-1;
              break;
           }
        }
      }
    }
    

#2


2  

first of all, it would be great if you could also share what is the actual output or error you get while running this program.

首先,如果您还可以分享运行此程序时获得的实际输出或错误,那将会很棒。

most of the time dynamic memory allocation is used when we do not know the actual size of data elements, but here you have already fixed the size of struct people student as 20

大多数时候动态内存分配是在我们不知道数据元素的实际大小时使用的,但是在这里你已经修改了struct people student的大小为20

 struct people student[20];

this is absolutely fine, but then you do malloc in while loop

这绝对没问题,但是你在while循环中做malloc

     student = malloc(sizeof(struct student);

you have already alloted 20 locations using array declaration, now malloc is not required. if you want to use dynamic memory allocation using pointers for learning purpose then you should first declare student as pointer to type struct people

你已经使用数组声明分配了20个位置,现在不需要malloc。如果你想使用指针进行动态内存分配以进行学习,那么你应该首先将student声明为指向struct人类的指针

struct people* student;

allocate memory dynamically in while loop

在while循环中动态分配内存

student=(struct people*) malloc(sizeof(struct people));

then access it

然后访问它

*(student+count)

hope this helps, if you still have doubts/problems edit the question and include the output/error you get while compiling/running this program.

希望这有帮助,如果你仍然有疑问/问题编辑问题并包括编译/运行该程序时得到的输出/错误。

#3


1  

Several issues with the Question code...

问题代码的几个问题......

1) Definition of main():

1)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:

它必须返回一个整数。在main()的末尾添加一个return语句,并创建一个正确的“CLEANUP”部分:

   printData(student, count);

CLEANUP:

   if(in_file)
      fclose(in_file);

   return(0);
}

2) Better handling of fopen() error condition:

2)更好地处理fopen()错误条件:

  if(( in_file = fopen(argv[1], "r")) == NULL)
  {
     printf("unable to open the file");
     goto CLEANUP;
  }

And, initialize the in_file pointer:

并初始化in_file指针:

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:

3)接下来,需要确定学生的确切定义。它是静态数组,还是指向动态分配数组的指针?我假设您想使用动态数组(给出问题文本)。但是,此假设与以下行冲突,后者将学生定义为静态数组:

  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:

4)现在,以下问题代码为每个学生分配一个新的(单独的)内存块:

     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:

5)看看人员结构:

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:

在指针和数组方面,问题代码似乎有些困难。代码试图将name和courseID字段定义为指针和数组。鉴于问题是动态分配东西,我选择朝那个方向发展。因此,此结构应更改为以下内容:

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:

6)因此,每次循环时,学生姓名将被放置在已分配的存储中,并由.name字段指向。所以,改变这个:

     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:

7)我不明白这一行的意图:

   if (strcmp((student[i].name, student[i].courseID) > 0))

I am inclined to eliminate it.

我倾向于消除它。


8) The following line has flaws:

8)以下行有缺陷:

      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.

'\ n'使输出看起来更好,每行一条记录。


9) Since student is a pointer to dynamically allocated memory (not a static array), change this:

9)由于student是指向动态分配的内存(不是静态数组)的指针,因此请更改:

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:

10)现在,完成解析数据的任务;由此:

     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:

11)现在,为了让生活更轻松,对数组进行排序。首先按courseID,然后按名称:

 ...  
     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:

12)使用printData()函数进行一些最后润色:

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

#4


0  

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

struct people {
    char name[10];//char *name[10] is array of pointer 
    char courseID[15];
    int grade;
};

void printData(struct people student[], int count);

int main(int argc, char* argv[]){
    FILE *in_file;
    char buffer[30];
    char *token, *del=",";
    int count=0;

    struct people student[20];

    if((in_file = fopen(argv[1], "r")) == NULL){
        printf("unable to open the file");
        return -1;//It is not possible to continue the process
    }

    while (fgets(buffer, sizeof(buffer), in_file)){
        //student = malloc(sizeof(struct people));//It is by securing an array already
        token = strtok(buffer, del);
        strcpy(student[count].name, token);
        token = strtok(NULL, del);
        strcpy(student[count].courseID, token);
        token = strtok(NULL, del);
        student[count].grade = atoi(token);
        count++;
    }
    fclose(in_file);
    printData(student, count);
}

int cmp(const void *a, const void *b){
    const char *x = ((const struct people*)a)->courseID;
    const char *y = ((const struct people*)b)->courseID;
    return strcmp(x, y);
}

void printData(struct people student[], int count){
    qsort(student, count, sizeof(struct people), cmp);//sort by courseID
    char *prev = "";
    int i;
    for(i=0; i<count; i++){
        if(strcmp(prev, student[i].courseID)!=0){
            prev = student[i].courseID;
            printf("\n%s\n", prev);
        }
        printf("%-9s %d\n", student[i].name, student[i].grade);
    }
}

#1


0  

  1. Change the definition of people to:

    将人员的定义更改为:

    struct people
    {
      char name[10];
      char courseID[15];
      int grade;
    };
    

    This assumes that name won't be longer than 9 characters and coursID won't be longer than 14 characters. If that is not true, change them accordingly.

    这假设名称不会超过9个字符,而coursID不会超过14个字符。如果不是这样,请相应地更改它们。

  2. The line:

    student = malloc(sizeof(struct student);
    

    is wrong in couple of ways.

    在某些方面是错误的。

    • student is already declared to be an array of people. You cannot assign it to point to memory allocated by malloc.

      学生已被宣布为一群人。您不能将其指定为指向malloc分配的内存。

    • struct student is not a type.

      struct student不是一种类型。

    That line can be removed.

    该行可以删除。

  3. The line

    strcpy(student[count].name, token);
    

    can cause problems if the length of token is longer than 10 (or whatever size you choose for name in people). The safer thing to do is use strncpy.

    如果令牌的长度超过10(或您为人名选择的任何大小),可能会导致问题。更安全的事情是使用strncpy。

    strncpy(student[count].name, token, 10);
    student[count].name[9] = '\0';
    
  4. You have not set the value of courseID anywhere. Yet, you are trying to print it in printData. You are doing the same thing for grade. You need to update the processing of input lines to set those correctly.

    您没有在任何地方设置courseID的值。但是,您正尝试在printData中打印它。你正在为年级做同样的事情。您需要更新输入行的处理以正确设置它们。

    Change the while loop to:

    将while循环更改为:

    while (fgets(buffer, sizeof(buffer), in_file))
    {
       token = strtok(buffer, del);
       strncpy(student[count].name, token, 10);
       student[count].name[9] = '\0';
       token = strtok(NULL, del);
       strncpy(student[count].courseID, token, 15);
       student[count].courseID[14] = '\0';
       token = strtok(NULL, del);
       student[count].grade = atoi(token);
       count++;
    }
    
  5. There are couple of syntax errors in printData. However, fixing those syntax errors does not take care of your printing requirements. It will be easier to print the data in the order that you want to if you sort the data. The following functions will help you sort the data.

    printData中有几个语法错误。但是,修复这些语法错误并不会影响您的打印要求。如果对数据进行排序,将按照您希望的顺序打印数据会更容易。以下功能将帮助您对数据进行排序。

    int compareStudent(const void* ptr1, const void* ptr2)
    {
       struct people* p1 = (struct people*)ptr1;
       struct people* p2 = (struct people*)ptr2;
       return (strcmp(p1->courseID, p2->courseID));
    }
    
    void sortData(struct people student[], int count)
    {
       qsort(student, count, sizeof(struct people), compareStudent);
    }
    

    You can call sortData before calling printData or call sortData first in printData. The logic for printing the data needs to be updated a little bit. Here's an updated printData.

    您可以在调用printData之前调用sortData,或者先在printData中调用sortData。打印数据的逻辑需要稍微更新一下。这是一个更新的printData。

    void printData(struct people student[], int count)
    {
      int i;
      int j;
    
      sortData(student, count);
    
      for(i=0; i<count; ++i)
      {
        printf("%s\n", student[i].courseID);
        printf("%s %d\n", student[i].name, student[i].grade);
        for ( j = i+1; j < count; ++j )
        {
           if (strcmp(student[i].courseID, student[j].courseID) == 0)
           {
              printf("%s %d\n", student[j].name, student[j].grade);
           }
           else
           {
              i = j-1;
              break;
           }
        }
      }
    }
    

#2


2  

first of all, it would be great if you could also share what is the actual output or error you get while running this program.

首先,如果您还可以分享运行此程序时获得的实际输出或错误,那将会很棒。

most of the time dynamic memory allocation is used when we do not know the actual size of data elements, but here you have already fixed the size of struct people student as 20

大多数时候动态内存分配是在我们不知道数据元素的实际大小时使用的,但是在这里你已经修改了struct people student的大小为20

 struct people student[20];

this is absolutely fine, but then you do malloc in while loop

这绝对没问题,但是你在while循环中做malloc

     student = malloc(sizeof(struct student);

you have already alloted 20 locations using array declaration, now malloc is not required. if you want to use dynamic memory allocation using pointers for learning purpose then you should first declare student as pointer to type struct people

你已经使用数组声明分配了20个位置,现在不需要malloc。如果你想使用指针进行动态内存分配以进行学习,那么你应该首先将student声明为指向struct人类的指针

struct people* student;

allocate memory dynamically in while loop

在while循环中动态分配内存

student=(struct people*) malloc(sizeof(struct people));

then access it

然后访问它

*(student+count)

hope this helps, if you still have doubts/problems edit the question and include the output/error you get while compiling/running this program.

希望这有帮助,如果你仍然有疑问/问题编辑问题并包括编译/运行该程序时得到的输出/错误。

#3


1  

Several issues with the Question code...

问题代码的几个问题......

1) Definition of main():

1)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:

它必须返回一个整数。在main()的末尾添加一个return语句,并创建一个正确的“CLEANUP”部分:

   printData(student, count);

CLEANUP:

   if(in_file)
      fclose(in_file);

   return(0);
}

2) Better handling of fopen() error condition:

2)更好地处理fopen()错误条件:

  if(( in_file = fopen(argv[1], "r")) == NULL)
  {
     printf("unable to open the file");
     goto CLEANUP;
  }

And, initialize the in_file pointer:

并初始化in_file指针:

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:

3)接下来,需要确定学生的确切定义。它是静态数组,还是指向动态分配数组的指针?我假设您想使用动态数组(给出问题文本)。但是,此假设与以下行冲突,后者将学生定义为静态数组:

  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:

4)现在,以下问题代码为每个学生分配一个新的(单独的)内存块:

     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:

5)看看人员结构:

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:

在指针和数组方面,问题代码似乎有些困难。代码试图将name和courseID字段定义为指针和数组。鉴于问题是动态分配东西,我选择朝那个方向发展。因此,此结构应更改为以下内容:

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:

6)因此,每次循环时,学生姓名将被放置在已分配的存储中,并由.name字段指向。所以,改变这个:

     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:

7)我不明白这一行的意图:

   if (strcmp((student[i].name, student[i].courseID) > 0))

I am inclined to eliminate it.

我倾向于消除它。


8) The following line has flaws:

8)以下行有缺陷:

      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.

'\ n'使输出看起来更好,每行一条记录。


9) Since student is a pointer to dynamically allocated memory (not a static array), change this:

9)由于student是指向动态分配的内存(不是静态数组)的指针,因此请更改:

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:

10)现在,完成解析数据的任务;由此:

     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:

11)现在,为了让生活更轻松,对数组进行排序。首先按courseID,然后按名称:

 ...  
     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:

12)使用printData()函数进行一些最后润色:

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

#4


0  

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

struct people {
    char name[10];//char *name[10] is array of pointer 
    char courseID[15];
    int grade;
};

void printData(struct people student[], int count);

int main(int argc, char* argv[]){
    FILE *in_file;
    char buffer[30];
    char *token, *del=",";
    int count=0;

    struct people student[20];

    if((in_file = fopen(argv[1], "r")) == NULL){
        printf("unable to open the file");
        return -1;//It is not possible to continue the process
    }

    while (fgets(buffer, sizeof(buffer), in_file)){
        //student = malloc(sizeof(struct people));//It is by securing an array already
        token = strtok(buffer, del);
        strcpy(student[count].name, token);
        token = strtok(NULL, del);
        strcpy(student[count].courseID, token);
        token = strtok(NULL, del);
        student[count].grade = atoi(token);
        count++;
    }
    fclose(in_file);
    printData(student, count);
}

int cmp(const void *a, const void *b){
    const char *x = ((const struct people*)a)->courseID;
    const char *y = ((const struct people*)b)->courseID;
    return strcmp(x, y);
}

void printData(struct people student[], int count){
    qsort(student, count, sizeof(struct people), cmp);//sort by courseID
    char *prev = "";
    int i;
    for(i=0; i<count; i++){
        if(strcmp(prev, student[i].courseID)!=0){
            prev = student[i].courseID;
            printf("\n%s\n", prev);
        }
        printf("%-9s %d\n", student[i].name, student[i].grade);
    }
}