1

我有一个包含学生姓名和成绩的文件,我想编写一个程序,可以根据用户选择对他们的成绩进行排序(如期中 1、期中 2)。我写了选择部分并打开文件,但我不知道如何让程序只读取文件的某些部分(例如,只有期中 1 年级)并只对它们进行排序。这是我到目前为止所写的;

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

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

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

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

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


const int STUDENTSMAX = 100;

Student students[STUDENTSMAX];
int i = 0;

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

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

  while (choice != 4);{


  switch (choice) {

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




    fclose(cfPtr);
   }

   system("PAUSE"); 
   return 0;
    }
4

1 回答 1

0

鉴于可能是一个有点自由格式的文本文件(基于显示的代码),阅读整个文件(有点像你已经在做的)并且只使用你需要的部分可能是有意义的。如果文本文件具有具有固定偏移量的非常特定的格式,您可以查找文件中的某些位置并读取特定列值,然后查找下一个偏移量并从下一行读取列值。但这可能比它的价值更麻烦,并且不会更有效率(如果有的话)。

话虽如此,要对结果进行排序,您可能仍然需要整个文件。例如,如果您只是读取并排序“期中 1”值,那么结果将只是排序的成绩,没有任何关联的姓名和学号。因此,在不了解目标的更多信息的情况下,您可能会考虑创建一个struct可以容纳单行(学号、姓名、姓氏、midterm1 等)的。然后创建一个数组并将每一行读入数组的一个元素。如果您知道预先存在多少行,则可以将数组分配在一个块中,否则您可能需要在增长时重新分配它。

读取整个数组后,您可以根据所需的值进行排序(例如,使用qsort.

提到这一点,现有显示的代码存在一些问题/问题:

  • 第二个 printf 的格式说明符 (%s) 少于参数。
  • 带有“您想做什么”问题的第三个 printf 缺少结束括号。
  • fprintf 不正确;它应该有一个文件句柄作为第一个参数。不过,我怀疑这可能是故意的printf
  • 最后一个while循环在它的右括号后面有一个无关的分号 (;),这意味着它有一个空的主体,而不是明显的预期printfswitch语句。
  • switch句话写得有点奇怪。我认为这是“未完成”的部分。但包括在内fclose似乎很奇怪。它可能应该在 main 的末尾else
  • 使用system("PAUSE");可能不是最好的选择。也许使用getch暂停输入会更有意义。

编辑 这里是一些附加信息,以回应您要求更多详细信息的评论。这对我来说听起来像是家庭作业,所以仅仅给出答案似乎并不正确。但这是一种方法:

  • 使用文件中的 6 个项目定义 a struct(基本上放入您当前已定义为局部变量的 6 个变量)。
  • 将局部变量(例如grades)声明为pointer您定义的 to 结构。
  • 用于malloc分配内存并将其分配给刚刚提到的指针。内存量可能是整个事情中最棘手的部分。的大小参数malloc将类似于numRecs * sizeof( yourstruct ). 问题是numRecs应该是什么。如果这是一项任务,并且您被告知将有多少条记录(最多),那么就使用它。但是,如果它是“未知的”,那么有几种处理方法。一种是只猜测一个数字(例如,100),然后在循环中读取它们时,realloc如果超过 100,则使用它们。另一种选择(可能效率较低)是使用两个循环 - 读取它们一次而不存储它们但是只需计算它们,然后分配已知大小并再次读取它们。我会使用 realloc 版本。
  • 将局部变量的使用替换为数组(即malloced)。例如,studentnumber您可以使用grades[arraypos].studentnumber. 当您阅读它们时,请记下有多少。然后,您可以使用qsort对数组进行排序。

编辑 2

  • 您的结构定义看起来是正确的,只是FILE *cfPtr;成员不应该在其中。它仍然应该是一个局部变量。
  • 为了便于使用,您可以将结构定义为typedef struct { ... } Student;. 这样你就可以在代码中使用Student而不是。struct Student请注意,我将名称大写(个人偏好的命名使其看起来不像变量名)。
  • 对于 malloc,您已经很接近了。但正如所写,它为单个记录分配空间。您将需要这样的东西:( name = malloc( 50 * sizeof( struct student )); 或者malloc( 50 * sizeof( Student ));如果您将其更改为使用 typedef。假设从文件中读取的记录不超过 50 条或更少。
于 2012-08-09T20:45:42.750 回答