0

私のプログラムの関数で、ファイルからこの構造体配列にデータをロードしようとしています:

/* database struct */
typedef struct node {
    char       name[MAX];
    char       address[MAX];
    long int   number;
}record_type;

record_type record[100];

機能は次のとおりです。

/* load database from disk */
void load_database() {
    char line[128];

    /* Set up database */
    database = fopen("database.txt", "r+w+a+");
    if(database == NULL) {
        printf("\n\tWARNING: No database found.");
        exit(1);
    }

    /* Get database file from disk */
    while(fgets(line, sizeof(line), database) != NULL) {
        sscanf(line, "%s %s %lu", record[rec_num].name,
            record[rec_num].address, &record[rec_num].number);

        /* keeps track of array size */
        rec_num++;
    }
}

私が抱えている問題は、sscanf との矛盾です。姓と名を含める場合、それらの間にスペースを入れることはできません。または、名を名前 [] に、姓を住所 [] に配置します。

入力しようとしているデータのサンプルを次に示します。

1.  Name: james manes       Address: 220 test addr      Number: 5558889999

"james manes" を name[] フィールドに、220 test addr を address[] フィールドに、5558889999 を構造体の number フィールドに入れる必要があります。これはまったく可能ですか?

このタイプの入力を管理するより効率的な方法はありますか?

4

2 に答える 2

1

scanf("%s"...入力内の空白で区切られた文字列を解析するため、解析する文字列にスペースが含まれていると機能しません。

正規表現を使用して必要なものを取得できますが、固定文字列をマーカーとして使用するため、代わりに使用strstrして文字列を引き出すことができます。

while(fgets(line, sizeof(line), database) != NULL) {
    char *Name = strstr(line, "Name:");
    char *Address = strstr(line, "Address:");
    char *Number = strstr(line, "Number:");
    if (Name && Address && Number) {
        Name += strlen("Name:");
        *Address = '\0';
        Address += strlen("Address");
        *Number = '\0';
        Number += strlen("Number:");
        strcpy(record[rec_num].name, Name);
        strcpy(record[rec_num].address, Address);
        sscanf(Number, "%lu", &record[rec_num].number);
        rec_num++; } }

これにより、名前とアドレスの周りのすべての空白も取り込まれることに注意してください。きれいにしたい場合は、先頭と末尾の空白を切り取ることができます。

于 2012-12-06T05:03:25.367 に答える
-2

まず、 http://www.cplusplus.com/reference/cstdio/fgets/をもう一度見てください。ここで、str引数がバッファーへのポインターであり (正しく提供されています)、numが読み取りたいmaxのバイト数であることがわかりますが、これは正しく提供されていません。

コードの一部で fgets に渡されるバイト数の問題は、sizeof演算子の不適切な使用です。sizeof 演算子は、おそらくご存知のように、指定されたtypeのサイズを「返します」 。sizeof に渡す型はポインター型です (C の配列は 99% ポインターと同じであるため)。ポインターのサイズは、実行しているシステムによって異なります (Intel x86 では 32 ビット、AMD64 では 64 ビット、ATmega AVR では 16 ビットなど)。したがって、64 ビット マシンを使用していると仮定すると、fgets が 64 ビット (つまり 8 バイト) のデータを「取得」できるようになりますが、これは望んでいるものではありません。では、どのような記述が正しいでしょうか。

while(fgets(line, sizeof(*line)*128, database) != NULL) {
    ...

ここで行っているのは、char ポインターcharに逆参照し、この配列のサイズを掛けることです。

次に、これが可能かどうかについての質問です。はい、可能です。私も今、自分自身に質問したいと思います。これを C で行う必要がありますか (つまり、プラットフォームは他の学習目的などをサポートしていません)、それとも C#、Java、Python でこれを実装できますか? もしそうなら、私はあなたがすることを強くお勧めします.

そして最後になりましたが、あなたのコードの有用性について私たちに尋ねています。その答えは実に単純です。いいえ。現在または固定された状態ではありません。あなたが抱えている問題とはるかに複雑な問題は、「実際の」データベース (MySQL など) + その API を使用して修正されます。

于 2012-12-06T03:02:32.960 に答える