1

我试图让程序读取一个文本文件,其中包含诸如“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 

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

编辑:这是我的输入文件;

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

PS 是的,这是在任何人问之前的功课,我的时间不多了,而且我已经尝试了好几天,没有任何扎实的进展。我被问到的主要是“

  1. 按降序排列所选考试的成绩,输出文件将仅包含三列:所选考试的姓名、姓氏和分数。
  2. 定义一个名为“student”的结构体,将每个学生的姓名、姓名和分数存储在同一个变量名下。因此,文件中的所有数据都将存储在一个名为“学生”的新数据类型数组中。”
4

2 回答 2

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()期望回调恰好采用 type 的两个参数const void*,因此将其更改为如下所示:

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

这将消除您看到的警告,但它实际上只是一个警告。你没有qsort()用正确的论据打电话。我们稍后再讨论,我在运行您的程序时发现了其他问题。

第三个问题是不处理文件打开失败,导致段错误(老师一般给段错误打分差),所以改成这样:

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

只是退出,你不能运行,没有必要再用永远无法达到的逻辑缩进。例如:

 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[]您在结构中声明的数组(请参阅&解释时的缺席namesurname给定的模式)。

然后,这段代码:

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

   }
   }        
   } 

...进入无限循环。一旦他们选择 1,结构将永远如此快速地排序和打印,因为没有选项可以处理任何其他退出选项,而且它飞得如此之快,用户无论如何都无法进入它。我把它改成了这样,这更明智一些:

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

注意break. 您以前没有突破switch()while()需要两者都做的地方。我修改的代码中没有while()周围switch()

现在,修改后的调用qsort() 应该向您显示输入未排序的原因。你有这个:

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

第二个参数可以是i,因为i知道你有多少元素。第三个参数需要是您要排序的成员的大小,而不是整数的大小(不太确定您是如何沿着这条路径徘徊的)。这就是排序结构被截断的原因。

从手册页:

   void qsort(void *base, size_t nmemb, size_t size,
              int(*compar)(const void *, const void *));

描述 qsort() 函数对具有大小为大小的 nmemb 元素的数组进行排序。基本参数 > 指向数组的开头。

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

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

由于您将在回调中往返void *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;
}

有关详细信息,请参阅此答案。

最后一点,main应该是int main(void),因为你不期待争论。

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

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

于 2012-08-11T15:01:55.240 回答
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 它应该是从文件中读取的实际学生人数。

于 2012-08-11T11:56:36.200 回答