0

私は C が初めてで、私のクラスでは、ファイル内のすべての項目を読み取り、それらを動的に作成されたリストでファイル順に返す関数を作成する必要があるプロジェクトがあります。ファイルの各行は 1 つの項目であり、次の形式になっています。

'<description>' <damage> <cost> <weight>

ファイル内のアイテムへのベース ポインターをファイル順に返すか、ファイルが存在しない場合は NULL を返すことになっています。

これまでの私のコードは次のとおりです。

item_t *ReadItemsFromFile(char *file)
{
typedef struct item item_t;
struct item
{
   char name[32];
   float cost, weight;
   int dam;
};FILE *fpin = fopen(file, "r");

if(fpin != NULL)
{
  item_t i[20];
  int n = 0;
  char line[sizeof(file)];
  while(fgets(line, sizeof(line), fpin) != NULL){
      (fscanf(fpin, " '%[^']' %d %f %f", i[n].name, &i[n].dam, &i[n].cost, &i[n].weight));
  fputs(i[n].name, stdout);
  n++;
}
} else {
  return NULL;
} 
  return(0);
}

コードをテストするために fputs を使用してきましたが、最初と最後の項目が意味不明になります。また、入れてみると

fputs(&i[n].dam, stdout);

そのため、構造体の他の変数をテストできますが、「互換性のないポインター型から 'fputs' の引数 1 を渡しています。

fscanfを使用して構造体変数に正確に渡しているのか、それとも別のものなのかはわかりません。

4

4 に答える 4

2

struct定義を関数の外に移動する必要があります。

行の長さの仕様が間違っています。行全体を取り込むのに十分な長さのバイト数を指定する必要があります。

fgets()行を取得するために使用するときfscanf()は、ファイルから読み取るために使用しないでください。fgets()ファイルからの読み取りに既に使用しています。sscanf()に含まれる文字列からデータを読み取るために使用しますline

上記は、プログラムに名目上有用な何かをさせるのに十分です。

アイテムのリストを返すには、要件として指定した「動的に作成されたリスト」のメモリを作成するために、実際に呼び出す必要がありますmalloc()(または他の同様の関数)。前もっていくつの項目があるかわからないので、いくつあるかを発見する方法が必要になるか、リストを動的に拡張できるメカニズムを使用する必要があります。

于 2013-08-03T01:35:45.203 に答える
1

問題の 1 つは、 を使用fgetsしてファイルから行を に読み込み、lineその行を無視して を使用fscanfして次の行から読み取ることです。sscanf代わりに、読み取ったばかりの行を解析するために使用する必要があります。fgetsまたは、まったく使用せずfscanf、while 条件を直接指定します。

while(4 == fscanf(fpin, " '%[^']'%d%f%f", i[n].name, &i[n].dam, &i[n].cost, &i[n].weight)) {
    fputs(i[n].name, stdout);
    n++; }

もう 1 つの問題は、文字lineを保持するのに十分な大きさを宣言することです。sizeof(char *)おそらく 4 または 8 だけで、行全体には十分な大きさではないため、行の一部しか読み取ることができません。ファイル内で最も長い行を保持するのに十分な大きさを宣言する必要があります。

struct item3 つ目の問題は、 andを関数に対してローカルとして宣言することです。これは、戻り値の型の一部として関数の外部でitem_t使用しようとすると、コードがコンパイルされないことを意味します。item_t関数宣言の前に、宣言をグローバル スコープに移動する必要があります。

4 つ目の問題は、 ( ) に読み込む項目配列をiローカル変数として宣言しているため、関数からそれを返すことができないことです。そうすると、返されるポインターがガベージを指します。 . ただし、常に NULL を返すため、その問題は発生しません。

于 2013-08-03T04:14:45.783 に答える
0

あなたの問題は、関数が文字列fputs()を印刷するためのものであるためです。他のものを印刷するには、を使用するか、標準出力に印刷する場合は、単に使用することをお勧めします。char *fprintf()printf()

意味不明なことをなくすには、ファイルが適切なエンコーディングで保存されていることを確認してください。テスト インベントリ ファイルを BOM なしの ANSI または UTF-8 (ANSI as UTF-8) として保存すると、すべて正常に機能しましたが、UTF-8 として保存すると、ファイルの先頭に 3 バイトが挿入され、プログラムはそれを実行できませんでした。私の最初のアイテムのために意味不明なことを吐き出します。

ReadItemsFromFile()ご覧のとおり、 を変更して、読み取った要素の数が格納さintれる へのポインタを受け入れるようにしました。これによりint、コードをテストできるようになりました。クラス。さらに、それはかなり粗雑でしたが、アイテムの配列がオンザフライで保存されているメモリブロックのサイズを変更するコードを追加しました(malloc()およびそれぞれmemcpy()必要stdlib.h)実行可能ファイルを持っていた環境では動作しなかったため実行しますが、うまくいく場合は、代わりに使用することをお勧めします。string.hrealloc()realloc()

\0また、各行の null ターミネータ文字を含めて、128 文字の任意のバッファ長を置いていることにも注意してください。これは、あなたに合ったものに調整できます。

そして、これが私が話していたコードです:

struct item
{
    char name[32];
    float cost, weight;
    int dam;
};
typedef struct item item_t;

item_t *ReadItemsFromFile(char *file, int *count)
{
    FILE *fpin = fopen(file, "r");
    int n = 0;
    item_t *items = NULL;

    if(fpin != NULL)
    {
        char line[128];
        while(fgets(line, 128, fpin) != NULL){
            item_t *newptr = (item_t *)malloc((n + 1) * sizeof(item_t));
            memcpy(newptr, items, n * sizeof(item_t));
            free(items);
            items = newptr;

            if (4 == sscanf(line, "'%[^']' %d %f %f\n", items[n].name, &items[n].dam, &items[n].cost, &items[n].weight)) {
                n++;
            }
        }

        fclose(fpin)
    } else {
        *count = 0;
        return NULL;
    }

    *count = n;

    return items;
}
于 2013-08-03T03:57:05.707 に答える