使程序读取文件的某些部分

时间:2012-08-09 17:17:52

标签: c file sorting

我有一个包含学生姓名和成绩的文件,我想编写一个程序,可以根据用户的选择对他们的成绩进行排序(如期中1,中期2)。我写了选择部分并打开文件,但我不知道如何使程序只读取文件的某些部分(例如只有Midterm 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;
    }

1 个答案:

答案 0 :(得分:0)

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

话虽如此,要对结果进行排序,您可能还需要整个文件。例如,如果您只是读取“midterm 1”值并对其进行排序,那么结果将只是排序等级而没有任何关联的名称和学号。因此,如果不了解更多关于目标的信息,您可以考虑创建一个可以容纳一行的struct(学生编号,姓名,姓氏,中期1等)。然后创建一个数组并将每行读入数组的元素。如果你知道前面有多少行,你可以在一个块中分配数组,否则你可能需要在增长它时重新分配它。

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

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

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

修改以下是一些其他信息,以回应您的评论,询问更多详情。这听起来像是家庭作业,所以只是给出答案似乎不对。但这是一种方法:

  • 使用文件中的6个项目定义struct(基本上放在您当前定义为局部变量的6个变量中)。
  • 将一个局部变量(例如grades)声明为您定义的结构pointer
  • 使用malloc分配内存并将其分配给刚才提到的指针。记忆量可能是整个事情中最棘手的部分。 malloc的尺寸参数类似于numRecs * sizeof( yourstruct )。问题是numRecs应该是什么。如果这是一个作业,并且你被告知会有多少记录(最多),那么就使用它。但是,如果它“未知”,那么有几种方法可以解决这个问题。一个是猜测一个数字(例如,100),然后在循环中读取它们,如果超过100则使用realloc。另一个替代方案(可能效率较低)将使用两个循环 - 读取它们一旦没有存储它们但只计算它们然后分配已知的大小并再次读取它们。我会使用realloc版本。
  • 将局部变量的使用替换为数组(malloc ed)。例如,您可以使用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个或更少。