Search code examples
cmemory-managementdynamic-memory-allocation

Reading file data to array of structures while allocating memory dynamically


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.

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

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

Solution

    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.

    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.

      • struct student is not a type.

      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.

      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.

      Change the while loop to:

      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.

      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.

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