如何使用结构正确地将文件内容传递给qsort?

时间:2012-08-11 11:24:16

标签: c arrays struct

我正在尝试让程序读取一个文本文件,其中包含“1001姓氏姓氏10 20 30”等信息,学生人数,姓名,姓氏和3年级。这是我的代码:

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

 struct Student {
     int number;
     char name[30];
     char surname[30];
     int midterm1,midterm2,midterm3;
 } Student;

 int comp(const void * aa, const void * bb)
 {
    struct Student a = *(struct Student*)aa;
    struct Student b = *(struct Student*)bb;
    if (a.midterm1==b.midterm1)
            return 0;
    else if (a.midterm1 < b.midterm1)
            return -1;
    else
            return 1;
  } // comp


  int main(void)
  {
      int choice,studentnumber,midterm1,midterm2,midterm3,i,n;
      char surname;
      FILE *cfPtr;

      struct student *name;
      name = malloc( 10 * sizeof(Student));

      if ((cfPtr = fopen("grades.txt", "r")) == NULL)
          return 1;

      const int STUDENTSMAX = 100;
      struct Student students[STUDENTSMAX];
      char buff[1024];
      while(1)
      {
          memset(buff, 0, sizeof(buff));
          fgets(buff, sizeof(buff) -1, cfPtr);
          if (feof(cfPtr)) {
              break;
          }
          sscanf(buff, "%d %s %s %d %d %d", &students[i].number, students[i].name, students[i].surname, &students[i].midterm1, &students[i].midterm2, &students[i].midterm3);
          printf("%4d %15s %15s %10d %10d %10d\n", students[i].number, students[i].name, students[i].surname, students[i].midterm1, students[i].midterm2, students[i].midterm3);
          i++;
      } // while

      while (!feof(cfPtr))
      {
          fscanf(cfPtr, "%d%s%s%d%d%d", &students[i].number, &students[i].name,&students[i].surname, &students[i].midterm1, &students[i].midterm2, &students[i].midterm3);
          printf("%4d%15s%15s%10d%10d%10d\n", students[i].number, students[i].name,students[i].surname, students[i].midterm1, students[i].midterm2, students[i].midterm3);
           i++;
      } // while

      printf("What would you like to do? \n"
      "1- Sort according to midterm 1\n"
      "2- Sort according to midterm 2\n"
      "3- Sort according to midterm 3\n"
      "4- Exit\n");
      scanf("%d",&choice);

      scanf("%d",&choice);
      switch (choice) {
          case 1:
              qsort(students, i, sizeof(struct Student), comp);
              for (n = 0;  n < i; n++) {
                  printf("%4d %15s %15s %10d %10d %10d\n", students[n].number, students[n].name, students[n].surname, students[n].midterm1);
              } // for
              break;    
          case 2:
              qsort(students, i, sizeof(struct Student), comp);
              for (n = 0;  n < i; n++) {
                  printf("%4d %15s %15s %10d %10d %10d\n", students[n].number, students[n].name, students[n].surname, students[n].midterm2);
              } // for
              break;   
          case 3:
              qsort(students, i, sizeof(struct Student), comp);
              for (n = 0;  n < i; n++) {
                  printf("%4d %15s %15s %10d %10d %10d\n", students[n].number, students[n].name, students[n].surname, students[n].midterm3);
              } // for
              break;                          
      } // switch
  } // main?                  
  fclose(cfPtr);


  system("PAUSE");  
  return 0;
  } // the editor failed to find the corresponding '{' !OP should fix this

此当前代码返回此错误:

95 C:\Users\UseR\Desktop\main.c [Warning] parameter names (without types) in function declaration 
95 C:\Users\UseR\Desktop\main.c [Warning] data definition has no type or storage class 
98 C:\Users\UseR\Desktop\main.c syntax error before string constant 
98 C:\Users\UseR\Desktop\main.c [Warning] data definition has no type or storage class 
 C:\Users\UseR\Desktop\Makefile.win [Build Error]  [main.o] Error 1 

该程序正在编译和工作没有任何问题,但它仍然给出错误,并没有排序。我在这里做错了什么?

编辑:这是我的imput文件;

100201 al beaver 40 50 70
100202 andrew matthews 30 90 75
100203 leah doga 60 55 80
100204 rob kurt 45 80 60
100205 aliah devon 65 70 50
100206 sally pir 70 40 85
100207 eric bekta 75 65 55
100208 nile coul 55 75 65
100209 mina umur 72 60 90
100210 john hot 73 63 87

P.S。是的,这是一个功课,在任何人问之前,我已经没时间了,而且我已经真正尝试了几天而没有任何稳固的进展。我问的主要是“

  
      
  1. 按递减顺序对所选考试的成绩进行排序,输出文件将只包含三列:姓名,姓氏和所选考试的分数。
  2.   
  3. 定义名为“student”的结构,以相同的变量名称存储每个学生的姓名,姓名和分数。因此,文件中的所有数据都将存储在名为“student”的新数据类型数组中。“
  4.   

2 个答案:

答案 0 :(得分:5)

你在这段代码中遇到很多问题,我将逐一介绍一下我所做的更改。由于这是家庭作业,我不会发布完全修改过的程序,但只有足够的信息(或将来发现这个的人)可以用来让你的代码正常工作。

首先,您不需要类型定义的结构。只需声明一个结构:

改变这个:

 typedef struct {
 int number;
 char name[30];
 char surname[30];
 int midterm1,midterm2,midterm3;
 } Student;

对此:

struct Student {
        int number;
        char name[30];
        char surname[30];
        int midterm1,midterm2,midterm3;
};

第二个问题是您的比较功能原型不正确。 qsort()期望回调采用const void*类型的两个参数,因此将其更改为如下所示:

int comp(const void * aa, const void * bb)

这将消除你看到的警告,但它确实只是一个警告。你没有用正确的参数调用qsort()。我们稍后会谈到,在运行程序时我发现了其他问题。

第三个问题是没有处理文件无法打开,导致分段错误(教师通常会给出seg错误的等级),所以不是这样:

 if ((cfPtr = fopen("grades.txt", "r")) == NULL)
    printf("File cannot be opened.\n");
 else {

退出,你无法运行,没有任何意义,使用永远无法达到的逻辑进行缩进。 E.g:

 if ((cfPtr = fopen("grades.txt", "r")) == NULL) {
      printf("File cannot be opened.\n");
      return 1;
 }

第四个问题是,你正在从文件中读取虚假输入而不是测试它。我更喜欢使用缓冲区和sscanf()而不是fscanf(),但这只是偏好。无论如何,我就是这样做的:

    const int STUDENTSMAX = 100;
    struct Student students[STUDENTSMAX];
    char buff[1024];
    while (1)
    {
            memset(buff, 0, sizeof(buff));
            fgets(buff, sizeof(buff) -1, cfPtr);
            if (feof(cfPtr)) {
                    break;
            }
            sscanf(buff, "%d %s %s %d %d %d", &students[i].number, students[i].name, students[i].surname, &students[i].midterm1, &students[i].midterm2, &students[i].midterm3);
             printf("%4d %15s %15s %10d %10d %10d\n", students[i].number, students[i].name, students[i].surname, students[i].midterm1, students[i].midterm2, students[i].midterm3);
            i++;
    }

注意,如果你走这条路,你必须添加#include <string.h>并使用memset()在每次迭代时重置缓冲区。另请注意,我取消引用您在结构中声明的char[]数组(在解释&和{{1}时,请参阅name的缺席给出的模式)。

然后,这段代码:

surname

......进入无限循环。一旦他们选择1,结构将被永久地分类和打印,因为没有选项可以处理任何其他选项退出,并且它飞得太快,用户无论如何都无法输入它。我把它改成了这个,这是更明智的一点:

scanf("%d",&choice);

 while (choice != 4) {


  switch (choice) {

       case 1:
            qsort(students,10,sizeof(int),comp);
        printf("%4d%15s%15s%10d%10d%10d\n", students[i].number, students[i].name,students[i].surname, students[i].midterm1);

   }
   }        
   } 

请注意 scanf("%d",&choice); switch (choice) { case 1: qsort(students, i, sizeof(struct Student), comp); for (n = 0; n < i; n++) { printf("%4d %15s %15s %10d %10d %10d\n", students[n].number, students[n].name, students[n].surname, students[n].midterm1, students[n].midterm2, students[n].midterm3); } break; } 。您以前没有突破breakswitch()您需要同时执行这两项工作的地方。我修改的代码中while()周围没有while()

现在,对switch() 的修改调用应该显示输入未被排序的原因。你有这个:

qsort()

第二个参数可以是qsort(students,10,sizeof(int),comp); ,因为i知道你有多少元素。第三个参数需要是您正在排序的成员的大小,而不是整数的大小(不太确定您是如何沿着该路径漫游)。这就是排序结构被截断的原因。

从手册页:

i
     

说明   qsort()函数使用大小为nmemb的元素对数组进行排序。基本参数&gt;指向数组的开头。

如你所见,它想要(按此顺序):

  • 你在排序什么?
  • 它有多少成员?
  • 每个成员的大小是多少?
  • 我应该使用什么回调函数来做出决定?

由于您在回调中往返 void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); void *,因此您需要对其进行修改:

Student

有关详细信息,请参阅this answer

最后一次,int comp(const void * aa, const void * bb) { struct Student a = *(struct Student*)aa; struct Student b = *(struct Student*)bb; if (a.midterm1 == b.midterm1) return 0; else if (a.midterm1 < b.midterm1) return -1; else return 1; } 应该是main,因为你不期待参数。

您需要进行一些其他修改,或者您可以根据我提供的反馈快速修复您所拥有的修改。我摆脱了所有未使用的值,你分配的结构(不确定是什么)并真正清理它。如果你想获得好成绩,我建议你也这样做。

还有很多我没有完全解释的,因为这个答案已经足够长了,我不想让你做更多的研究。

答案 1 :(得分:0)

比较功能应该有两个指向学生的指针。它应该是这样的:

 int comp(const Student * a, const Student * B)
 {
 if (a->midterm1==b->midterm1)
 return 0;
 else
 if (a->midterm1 < B->midterm1)
        return -1;
 else
  return 1;
 }

qsort调用应该是这样的

qsort(students, 10, sizeof(Student), comp);

最后为什么你将10传递给qsort,它应该是从文件中读取的实际学生数。