3

私はC99プログラムを作成していますが、コードの少しの冗長性から抜け出すためにいくつかの助けが必要です。次のコードを関数の2つの呼び出しに変換したいのですが、その方法がわかりません。

2つのファイル(それぞれに15の入り口があります)を読み取り、その内容を2つの配列に入れたいと思います。問題は、これらの配列のデータ型が異なることです。

これが私が持っているものです:

typedef char string[30];

int
    _vInt[15];

string
    _vString[15];

FILE
    *_fInt,
    *_fString;

int main(){

      ...

      for(int i = 0; !feof(_fInt) && i < 15; ++i){
           fscanf(_fInt, "%d", &_vInt[i]);
           ...
      }

      for(int i = 0; !feof(_fString) && i < 15; ++i){
           fscanf(_fString, "%s", _vString[i]);
           ...
      }

      ...

 }

だから、これを二度使いたくないfor。代わりに、関数を2回呼び出したいと思います。

readFile(_fInt, "%d", _vInt);
readFile(_fString, "%s", _vString);

問題は、関数のプロトタイプがどうあるべきか、またそれをどのように使用すべきかがわからないことです。

はい、醜いvoid *ソリューションを使用しても問題ありません...

4

4 に答える 4

1

別の解決策は、 readFile() 関数で列挙型とテーブルを使用することです。

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

// Put in Header file
typedef char string[30];
typedef enum {
    ITInt    =  0,
    ITString =  1,
    ITMax
} InputTypes;

// Should be in module with readFile()
struct inputTypeEntry_s{
    const char *format;
    size_t sz;
};

struct inputTypeEntry_s inputTypeLUT[ITMax] = {
    { "%d", sizeof(int) },      // ITInt
    { "%s", sizeof(string) },   // ITString
};

int readFile(FILE *fp, InputTypes type, void *data) {
    char *ptr = (char *)data;
    for(int i = 0; !feof(fp) && i < 15; ++i){
        fscanf(fp, inputTypeLUT[type].format, ptr + (i * inputTypeLUT[type].sz) );
    }
    return 0;
}
于 2013-01-22T01:04:49.473 に答える
1

マクロを使用できます。

#define readFile(file, fmt, arr) \
    for (int i = 0; !feof(file) && i < 15; ++i) { \
        fscanf(file, fmt, arr[i]); \
    }

readFile(_fInt, "%d", &_vInt);
readFile(_fString, "%s", _vString);
于 2013-01-22T00:17:52.410 に答える
0

C11 の機能を使用できるとおっしゃっていたので、C11 型ジェネリック式を使用した例を次に示します。フォーマット文字列を渡すための要件を削除するためにも使用しました。

#include <stdio.h>

typedef char string[30];

#define generic_arg(X) _Generic(X, string: X, \
                                   default: &X)

#define generic_format(X) _Generic(X, string: "%s", \
                                      int:    "%d")

#define readFile(file, variable) for (int i = 0; i < 15; i++)            \
                                 {                                       \
                                     fscanf(file,                        \
                                            generic_format(variable[i]), \
                                            generic_arg(variable[i]));   \
                                 }

int main(void)
{
    int _vInt[15];
    string _vString[15];

    FILE *_fInt = fopen("ints", "r");
    FILE *_fString = fopen("strings", "r");

    readFile(_fInt, _vInt);
    readFile(_fString, _vString);

    for (int i = 0; i < 15; i++)
    {
        printf("%d %s\n", _vInt[i], _vString[i]);
    }

    fclose(_fInt);
    fclose(_fString);

    return 0;
}

これが本当に素晴らしい例かどうかはわかりません.2forループのソリューションよりも確かに複雑ですが、要件を満たしていると思います.

于 2013-01-22T01:00:21.337 に答える
0

タイプを に抽出できますが、(void *)きれいにはなりません。

void foo(FILE *file, const char *format, void *arr, size_t size) {
  for(int i = 0; !feof(file) && i < 15; ++i){
       fscanf(file, format, ((char *)arr) + (size * i));
       ...
  }      
}

関数呼び出しは次のようになります

foo(_fInt, "%d", (void *)&_vInt, sizeof(int))
于 2013-01-22T00:07:09.317 に答える