1

空白で区切られたテキスト ファイルからベクトルを形成する変数をスキャンしたいのですが、つまずきは (私にとってはよくあることですが) エレガンスの欠如です。

現在、私のスキャン コードでは、ファイルの最初の要素としてベクトルのサイズを示す必要があります。

7 : 1 3 6 8 -9 .123 1.1

「7」は空白を調べることで判断できるため、これは気になります。

fscanf()、strtok() などのさまざまな形式を試してみましたが、すべて総当たりのようです。lex/yacc (利用できません) に頼ることなく、誰かが次のものよりもエレガントなものを提案できますか?

typedef struct vector_tag
{
    int Length;
    double * value;
} vector;

vector v;

char buf[BIG_ENOUGH], key[BIG_ENOUGH], val[BIG_ENOUGH];

void scan_vector(FILE * fh)
{
    int i, length;
    double * data;
    char * tok;

    do {
        if (feof(fh)) return;
        fgets(buf, sizeof buf, fh);    
    } while (2 != sscanf(buf,"%[^:]:%[^\n\r]",key,val));

    length      =
    v.Length    = strtol(key,NULL,10);
    data        =
    v.value     = malloc(length * sizeof(double));

    tok = strtok(val, " "); /* I'd prefer tokenizing on whitespace */
    for (i = 0; i++ < v.Length; ) {
        * data++ = strtod(tok,NULL);;
        tok = strtok(NULL, " "); /* Again, tokenize on whitespace */
    }
}

解決策:チェックされた回答のおかげで、実装しました:

static int scan_vector(FILE * fh, vector * v)
{
    if (1 == fscanf(fh,"%d:",& v->length))
    {
        int         i;

        v->value    = malloc(v->Length * sizeof(double));

        assert (NULL != v->value);

        for (i = 0; i < v->Length; i++)
        {
            if (fscanf(fh,"%lf",v->value + i) != 1) return(0);
        } 
        return(1);
    } 
    return(0);
} /* scan_vector() */
4

4 に答える 4

1

次のようなもので何が問題なのですか:

int scan_vector(FILE *fh)
{
    char pad[2];
    int i;
    if (fscanf(fh,"%d %1[:]", &v.Length, &pad) != 2)
        return -1;
    v.value = malloc(v.Length * sizeof(double));
    for (i = 0; i < v.Length; i++) {
        if (fscanf(fh, "%lf", &v.value[i]) != 1)
            return -1;
    }
    return 0;
}

これは scanf でベクトルを読み取ろうとし、問題があった場合は -1 エラー コードを返します。

これよりもはるかに複雑なことをしたい場合は、少なくとも flex を使用した方がよいでしょう (bison ではないにしても)。

于 2009-06-30T19:08:37.830 に答える
0

ファイルの最初のエントリとしてベクトルのサイズを必要としないバージョンを次に示します。

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

#define LINE_MAX 256
#define VECTOR_SIZE_MAX 32

struct vector
{
    size_t size;
    double *values;
};

// returns 1 on error
_Bool scan_vector(FILE *file, struct vector *v)
{
    char buffer[LINE_MAX];
    if(!fgets(buffer, sizeof(buffer), file))
        return 1;

    double values[VECTOR_SIZE_MAX];

    size_t size = 0;
    errno = 0;

    for(char *head = buffer, *tail = NULL;; ++size, head = tail)
    {
        while(isspace(*head)) ++head;
        if(!*head) break;

        if(size >= VECTOR_SIZE_MAX)
            return 1;

        values[size] = strtod(head, &tail);
        if(errno || head == tail)
            return 1;
    }

    v->size = size;
    v->values = malloc(sizeof(double) * size);
    if(!v->values) return 1;

    memcpy(v->values, values, sizeof(double) * size);

    return 0;
}

int main(void)
{
    struct vector v;
    while(!scan_vector(stdin, &v))
    {
        printf("value count: %u\n", (unsigned)v.size);
        free(v.values);
    }

    return 0;
}

最大行サイズとエントリ数は、パフォーマンス上の理由と怠惰から固定されています。

于 2009-06-30T20:25:37.270 に答える
0

使用する場合realloc()、初期値で十分に割り当てられない場合は、いつでも追加のメモリを要求できますmalloc()n一般的な戦略は、任意のアイテムを割り当てて開始することです。スペースが不足するたびにn、バッファーを2倍にしてサイズを変更します。

または、配列の代わりにリンク リストを使用することもできます。リンクされたリストは、配列よりも挿入と追加を適切に処理しますが、インデックスによって項目にアクセスする機能を放棄します。

于 2009-06-30T18:24:37.987 に答える
0

ベクトルの大きさはどのくらいですか?
1つの方法は、

  • 行をスキャンしてローカルバッファーに入れます(これは私が推測する1つのベクターデータです)
  • そのローカル バッファをスキャンして、空白区切り文字をカウントします (コーディングは非常に簡単です)。
  • 次に、正しい割り当てを行います
  • そして、ベクトルを初期化します

ご覧のとおり、ディメンション'7'は入力の一部である必要はありません。
可能な限り長い行に十分な大きさのローカル バッファーが 1 つだけ必要です。
そして、それに対するいくつかのエラー処理:-)

于 2009-06-30T18:34:30.107 に答える