繁体   English   中英

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

[英]Reading file data to array of structures while allocating memory dynamically

我需要帮助解决以下代码。 使用gcc编译代码后,它可以像./compiledFile inputFile.txt一样运行。在这种情况下,对于每种变量名称和courseID,在为每个变量动态分配内存时,应该让inputFile.txt读取它,但是我的代码无法正常工作。 我最不了解并且需要帮助的地方是分配内存,将数据插入结构并打印数据,如下例所示。 通过这段代码,您可以看出我是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)
    }
  }
}

data.txt文件包含以下内容,以逗号分隔:

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

打印时,它应如下所示:

MATH 1324
John 90
Omondi 89
David 90

SCI 1401
David 88

首先,如果您还可以共享运行此程序时得到的实际输出或错误,那将是很好的。

在大多数情况下,当我们不知道数据元素的实际大小时,将使用动态内存分配,但是在这里,您已经将struct people student的大小固定为20

 struct people student[20];

这绝对没问题,但是您可以在while循环中执行malloc

     student = malloc(sizeof(struct student);

您已经使用数组声明分配了20个位置,现在不需要malloc。 如果您想使用带有指针的动态内存分配用于学习目的,则应首先将学生声明为键入struct people的指针

struct people* student;

在while循环中动态分配内存

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

然后访问它

*(student+count)

希望这对您有帮助,如果您仍然有疑问/问题,请编辑问题,并包括在编译/运行此程序时遇到的输出/错误。

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

1)main()的定义:

int main(int argc, char* argv[])

它必须返回一个整数。 在main()的末尾添加return语句,并进行适当的“ CLEANUP”部分:

   printData(student, count);

CLEANUP:

   if(in_file)
      fclose(in_file);

   return(0);
}

2)更好地处理fopen()错误情况:

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

并且,初始化in_file指针:

int main(int argc, char* argv[])
{
  FILE *in_file = NULL;

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

  struct people student[20];

更改为:

  struct people *student = NULL;

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

     student = malloc(sizeof(struct people));

但是,需要的是所有学生记录都在同一块内存中的一个阵列中。 因此,需要的是扩展一块内存,以便在读取学生记录时包括它们,如下所示:

  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)看一下人员结构:

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

看起来问题代码在涉及指针和数组时有些困难。 该代码正在尝试将name和courseID字段定义为指针和数组。 鉴于问题在于动态分配内容,我选择朝这个方向发展。 因此,此结构应更改为以下内容:

struct people
{
  char *name;
  char *courseID;
  int   grade;
};

6)因此,每次循环时,学生姓名都将放置在分配的存储中,并由.name字段指向。 因此,更改此:

     token = strtok(buffer, del);
     strcpy(student[count]->name, token);
     count++;
  }

对此:

     token = strtok(buffer, del);
     student[count].name = strdup(token);
     count++;
  }

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

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

我倾向于消除它。


8)以下行有缺陷:

      printf("%s  %s", student[i].name, student[i].grade)

将其更改为此值以打印整数grade (并且不要忘记结尾的分号):

      printf("%s  %d\n", student[i].name, student[i].grade);

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


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

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

对此:

void printData(struct people *student, int count)

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

     token = strtok(buffer, del);
     strcpy(student[count].name, token);
     count++;
  }

对此:

     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)现在,为了使生活更轻松,对数组进行排序。 首先按CourseID,然后按名称:

 ...  
     count++;
  }

  /** Sort the array by coursID, then by name. **/
  qsort(student, count, sizeof(*student), CmpStudentRecs);

  printData(student, count);
 ...

这将需要附加的“比较学生记录”功能:

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)使用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);
  }
}

成品。 输出:

SLES11SP2:~/SO> ./test data.txt
MATH 1324
   David  90
   John  90
   Omondi  89
SCI 1401
   David  88
SLES11SP2:~/SO> 

SPOILER

  1. 更改的定义people来:

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

    假设name不能超过9个字符,而coursID不能超过14个字符。 如果不正确,请相应地更改它们。

  2. 该行:

     student = malloc(sizeof(struct student); 

    在几种方面是错误的。

    • student已经被宣布为people 您不能将其分配为指向malloc分配的malloc

    • struct student不是一个类型。

    该行可以删除。

  3. 线

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

    可能会造成问题,如果长度token长于10 (您选择或任何大小namepeople )。 较安全的方法是使用strncpy

     strncpy(student[count].name, token, 10); student[count].name[9] = '\\0'; 
  4. 您尚未在任何地方设置courseID的值。 但是,您正在尝试在printData打印它。 你的grade是一样的。 您需要更新输入行的处理以正确设置这些行。

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

    您可以拨打sortData调用之前printData或致电sortData在第一printData 打印数据的逻辑需要一点点更新。 这是更新的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; } } } } 
#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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM