1

動的に割り当てられた構造体 (DBrecord) へのポインターの配列を作成し、その配列に別のファイルからの入力を入力する必要があります。これにアプローチする方法がわからない。

データ ファイルには、最初にエントリ数があり、その後に特定の順序でエントリが続きます。

エントリー数

姓 名 学生 ID 年 gpa expGradYear

例:

1

Doe John 12345678 シニア 3.14159 2015

これが私がこれまでに持っているコードです:

class.h

typedef enum {firstYear, sophomore, junior, senior, grad} class;

main.c

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

int main(){

//DBrecord is name for structure
struct DBrecord{
int DBrecordID;     //ID for each entry, range 0-319
char *last;         //student last name
char *first;        //student first name
char studentID[8];  //student ID
int age;            //student age
class year;         //year in school
float gpa;          //GPA
int expGradYear;    //expected graduation year
};
int numEntries;     //total number of entries, first num in data file
struct DBrecord **ptrToDB;

//scan first int in data file and assign to numEntries
scanf("%d", &numEntries);

//allocate memory for structures, each is 36 bytes
*ptrToDB = malloc (sizeof(struct DBrecord) * numEntries);

//free allocated memory
free(ptrToDB);

//build an array of pointers to dynamically allocated structures
//fill that array with input from data file

//build 7 arrays of pointers to DBrecords, one for each field except DB ID
//sort each a different way
//note the 7 arrays are pointers, no copying

//print each of the 7 sorted arrays

return 0;
}
4

2 に答える 2

3

この問題の見方について、いくつかの断片を紹介できます。

まずclass、多くのオブジェクト指向プログラミング言語 (C++ を含む) では名前はキーワードであり、変数の名前にすることはできないため、変数に名前を使用することは避けます。

構造体 DBrecord

typedef を使用することをお勧めします。次に、「struct DBrecord」を使用せずに、「DBrecord」だけで構造体変数を宣言できます。しかし、それはオプションです。これはどのように見えるかです:

typedef struct {
   int DBrecordID; // ID for each entry
   char *lastName;
   char *firstName;
   char studentID[8];
   ...
} DBrecord;

ファイルからの読み込み

この宿題では、ファイルの先頭にレコードの数があるため、「余分な」注意を払う必要はありません。ロードするだけです。

ファイルが次のようになっているとします。

2
Doe John 12345678 senior 3.14159 2015
Carl Boss 32315484 junior 2.71 2013

したがって、ファイルに対して最初に行うことは、ファイルを開くことです。

ファイルを操作するポータブルな方法は、FILE ポインターを使用することです。それを見せてください(stdio.h含める必要があります):

FILE *filePtr; // Define pointer to file
if((filePtr = fopen("records.txt", "r")) == NULL) // If couldn't open the file
{
   printf("Error: Couldn't open records.txt file.\n"); // Printf error message
   exit(1);  // Exit the program
}

次に、 fgets() を使用して行単位で読み取るか、 fgetc() を使用して文字単位で読み取ることにより、ファイルから行単位で読み取ることができます。これは、レコード数を読み取る方法です (最初の行にあり、ファイルを開いたばかりであることを思い出してください。ファイルの先頭にいます)。

char buffer[100]; // Define the buffer
fgets(buffer, 100 /* size of buffer */, filePtr);

現在、バッファには最初の行 (\n 文字なし) - レコード数が含まれています。num の文字を整数に変換し続けます (ここstdlib.hにも含める必要があります)。

int numOfRecords = atoi(buffer);

十分な DB レコードの割り当て

レコードの数がわかったので、それらに十分なスペースを割り当てることができます。ポインターの配列を使用します。

DBrecord **recs;
recs = (DBrecord **) malloc(sizeof(DBrecord *) * numOfRecords);

ポインターの配列を作成したので、個々のポインターをすべて DBrecord として割り当てる必要があります。使用サイクル:

int i;
for(i = 0; i < numOfRecords; i++)
{
   recs[i] = (DBRecord *) malloc(sizeof(DBrecord));
}

これで、次のように配列要素 (= 個々のレコード) にアクセスできます。

recs[0]->lastname /* two possibilities */
*(recs[0]).lastname

など。

ファイルからの値で配列を埋める

これで、宿題を終わらせるためのすべてがわかりました。このようにして配列を埋めます:

int i;
for(i = 0; i < numOfRecords; i++)
{
   // Content of cycle reads one line of a file and parses the values into recs[i]->type...
   /* I give you small advice - you can use fgetc(filePtr); to obtain character by character from the file. As a 'deliminer' character you use space, when you hit newline, then the for cycle continues.
   You know the order of stored values in the file, so it shouldn't be hard for you.
   If you don't get it, let me now in comments */
}

なんとなく分かりやすくなりましたか?

編集: main の引数としてのファイル名

通常、引数 (値) をプログラムに「渡す」方法は 2 つあります。彼らです:

./program < records.txt   // Here the file's name is passed to program on stdin
./program records.txt    // Here the file's name is passed as value in `argv`.

もし選べるなら、2番目を強くお勧めします。したがって、main を次のように定義する必要があります。

int main(int argc, char *argv[])  // this is important!
{
   // code

   return 0;
}

argcプログラムに渡された引数の数を示す整数です。argvそれらを格納する配列です。最初の引数がプログラムの名前であることを思い出してください。したがって、確認する必要がある場合は、次のようにします。

if(argc != 2)
{
  printf("Number of arguments is invalid\n");
  exit(1); // exit program
}

次に、文字列「records.txt」の代わりに関数にargv[1]入れるだけです。fopen

編集 2: stdin からファイルの名前を読み取る

レコード ファイルの名前が 経由./program < records.txtでプログラムに渡される場合、別の方法を実行する必要があります。つまり、"records.txt" (引用符なし) がプログラムの標準入力に渡されます (リダイレクトされます)。

したがって、これを処理するには、次のようにします。

char filename[50]; // buffer for file's name
scanf("%s", &filename); // reads standard input into 'filename' string until white character appears (new line, blank, tabulator).

次に、目的のファイルの名前をfilename文字列で取得します。

于 2012-04-09T17:07:04.583 に答える
1

どこから始めて、どこから始めて……。

//allocate memory for structures, each is 36 bytes
mem = (double *)malloc(36*numEntries);
  1. malloc はmalloc (sizeof (struct DBRecord) * numEntries);

  2. malloc 2aの結果をキャストしないでください。あなたが忘れてしまったstdlib.h
  3. なぜ含めるのclass.hですか?
  4. ポインターの配列doubleは ではなく、代わりに

    struct DBRecord **ptrToDB;
    *ptrToDB = malloc (sizeof (struct DBRecord) * numEntries);
    

これで始められるはずです。

次に、free()関数を終了する前に最後に行う必要があります (はい、main は関数です)。

次の部分のコードを挿入する必要があります。宿題はできません。

于 2012-04-09T16:31:25.913 に答える