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、1 つの行 (学生番号、名前、姓、中間期 1 など) を保持できる を作成することを検討できます。次に、それらの配列を作成し、各行を配列の要素に読み取ります。前もって存在する行数がわかっている場合は、配列を 1 つのチャンクに割り当てることができます。

配列全体を読み取ったら、目的の値に基づいて並べ替えることができます (たとえば、qsort.

前述のとおり、既存の表示されているコードにはいくつかの問題があります。

  • 2 番目の printf には、パラメーターよりも少ない書式指定子 (%s) があります。
  • 「何をしたいですか」という質問を含む 3 番目の printf には、閉じ括弧がありません。
  • fprintf が正しくありません。最初のパラメーターとしてファイル ハンドルが必要です。しかし、それはおそらく意図されていたのではないprintfかと思います。
  • 最後のループには、閉じ括弧の後に無関係なセミコロン (;) があります。これは、明らかに意図されたステートメント whileではなく、空の本体があることを意味します。printfswitch
  • ステートメントは、switch書かれているように少し奇妙です。それが「未完成」の部分だと思います。しかしfclose、それを含めると奇妙に思えます。おそらく main の最後にあるはずelseです。
  • を使用するsystem("PAUSE");ことは、おそらく最良の選択ではありません。おそらく、 を使用getchすると、入力のために一時停止する方が理にかなっているでしょう。

編集 ここに、詳細を求めるコメントに対する追加情報をいくつか示します。これは私には宿題のように聞こえるので、答えを出すだけでは正しくないようです。しかし、ここにそれを行う1つの方法があります:

  • ファイルにある 6 つの項目でa を定義structします (基本的に、現在ローカル変数として定義している 6 つの変数に入れます)。
  • ローカル変数 (例: grades) を、pointer定義した to 構造体として宣言します。
  • mallocメモリを割り当て、それを前述のポインタに割り当てるために使用します。メモリの量は、おそらくこの全体の中で最も難しい部分です。のサイズ パラメータは のmallocようなものになりますnumRecs * sizeof( yourstruct )。問題は、どうあるnumRecsべきかです。これが割り当てであり、レコードの数 (最大) が通知された場合は、それをそのまま使用してください。ただし、それが「不明」である場合は、それに対処する方法がいくつかあります。1 つは数字 (たとえば 100) を推測し、100reallocを超えた場合にループでそれらを読み取る方法です。もう 1 つの方法 (おそらくあまり効率的ではありません) は、2 つのループを使用することです。それらを数えてから、既知のサイズを割り当てて、それらを再度読み取ります。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 以下ではないことを前提としています。
于 2012-08-09T20:45:42.750 に答える