0

次の形式のテキストファイルを読み取る機能があります

 string int int
 string int int
 string int int

テキストファイルの値を変数に代入する関数を書きたいのですが、テキストファイルのフォーマットが

string int
string int
string int

その場合、最後の int 変数の値を 1 に設定したいと思います。これまでのコードは最初の例で動作しますが、2 番目のシナリオを動作させるのに少し行き詰まっています。

void readFile(LinkedList *inList, char* file)
    {
    char tempName[30];
    int tempLoc, tempNum;

    FILE* f;
    f = fopen(file, "r");
    if(f==NULL) 
        {
        printf("Error: could not open file");
        }
    else
        {
        while (fscanf(f, "%s %d %d\n", tempName, &tempLoc, &tempNum) != EOF)
            {
            insertFirst (inList, tempName, tempLoc, tempNum);
            }
        }   
    }
4

1 に答える 1

3

2 番目のケースでは、fscanf は 3 ではなく 2 を返します。したがって、コードを次のように書き直すことができます。

while (1) {
    int ret = fscanf(f, "%s %d %d\n", tempName, &tempLoc, &tempNum);
    if (ret == EOF) {
        break;
    }
    if (ret == 2) {
        tempNum = 1;
    } else if (ret != 3) {
        // line appear invalid, deal with the error
    }
    insertFirst (inList, tempName, tempLoc, tempNum);

}

よりハックな方法は、fscanf を呼び出す前に tempNum を 1 に設定し、上記のように EOF をチェックすることです。しかし、上記のコードはより明確だと思います。

編集:オーバーフローを避けるために、これはより良いでしょう。コードのパフォーマンスは向上しますが、これを書くのは難しくなります。上記と同じように、エラー条件のコードを書いていませんが、間違いなくそれらを処理したい

char lineBuf[255];
while (fgets(lineBuf, sizeof(lineBuf), f) != NULL) {
    int spaceIdx, ret;
    const int len = strlen(lineBuf);
    if (len == (sizeof(lineBuf) - 1) {
         // line is too long - either your buf is too small and you should tell the user
         // that its input is bad
         // I recommend to treat this as an error
    }
    lineBuf[len - 1] = '\0'; // remove \n
    --len;  // update len, we've removed one character
    if (isspace(*lineBuf)) {
        // error, line should not start with a space
    }
    spaceIdx = strcspn(lineBuf, "\t ");
    if (spaceIdx == len) {
        // error, no space in this line
    }

    // Ok, we've found the space.  Deal with the rest.
    // Note that for this purpose, sscanf is a bit heavy handed (but makes the code
    // simpler). You could do it with strtol.
    // Also, the first space in the format string is important, so sscanf skips 
    // all the space at the beginning of the string.  If your format requires only
    // one space between fields, you can do sscanf(lineBuf + spaceIdx + 1, "%d %d"...

    ret = sscanf(lineBuf + spaceIdx, " %d %d", &tempLoc, &tempNum);
    if (0 == ret) {
        // error, no ints
    }
    else if (1 == ret) {
        tempNum = 1;
    }

    // at that point, you could copy the first part of lineBuf to tempName, but then
    // you have to deal with a potential overflow (and spend time on an useless copy),
    // so use lineBuf instead

    lineBuf[spaceIdx] = '\0';

    insertFirst (inList, lineBuf, tempLoc, tempNum);
}
于 2013-05-19T04:32:53.437 に答える