4

ファイルに数行の整数があります。例:

100 20 300 20 9 45 -1
101 80 80 2 80 2 50 3 70 -1

最初の2文字を読み込んで整数変数に格納し、残りの文字を文字列に格納して、後で繰り返すことができるようにします。

do {
    fscanf(file, "%d %d", &var1,&var2);
    }while(!feof(file));

次に、残りの行をスキャンして、次の行に移動して繰り返します。しかし、残りの行をスキャンしてvar3文字列にする方法がわかりません

..何か案は?

4

2 に答える 2

8

これがあなたが最初にすることです。入力データを完全scanf("%s")に制御できない限り、使用することを考えないでください。それ以外の場合は、バッファオーバーフローが発生する可能性があります。

この回答は、ユーザー入力に安全に使用できる方法を示しておりfgets、バッファオーバーフローの検出/回避、およびラインクリアを提供します。これは、任意の入力ストリームに簡単に適合させることができます。

行(および行全体)を文字列として取得し、最大サイズがわかったら、次のコマンドを使用できます。

char strBuff[1000]. str1[1000]; // Ensure both big enough.
:
// Use /getLine/fgets to get the line into strBuff.
:
int numScanned = sscanf (strBuff, "%d %d %[^\n]", &int1, &int2, str1);

フォーマット指定子が行うことは、%[^\n]任意の数の非改行文字をスキャンして文字列にすることです。[]文字クラスを表し、 「次の文字以外の^すべてに一致し、(非)一致に使用される文字は改行です」という意味です\n

この回答の下部には、標準の引用が続きます(a)


たとえば、次の関数を使用します。

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

#define OK       0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
    int ch, extra;

    // Get line with buffer overrun protection.
    if (prmpt != NULL) {
        printf ("%s", prmpt);
        fflush (stdout);
    }
    if (fgets (buff, sz, stdin) == NULL)
        return NO_INPUT;

    // If it was too long, there'll be no newline. In that case, we flush
    // to end of line so that excess doesn't affect the next call.
    if (buff[strlen(buff)-1] != '\n') {
        extra = 0;
        while (((ch = getchar()) != '\n') && (ch != EOF))
            extra = 1;
        return (extra == 1) ? TOO_LONG : OK;
    }

    // Otherwise remove newline and give string back to caller.
    buff[strlen(buff)-1] = '\0';
    return OK;
}

次のプログラムで:

int main (void) {
    int rc, numScanned, int1, int2;;
    char strBuff[100], str1[100];

    rc = getLine ("Yes> ", strBuff, sizeof(strBuff));
    if (rc == NO_INPUT) {
        // Extra NL since my system doesn't output that on EOF.
        printf ("\nNo input\n");
        return 1;
    }

    if (rc == TOO_LONG) {
        printf ("Input too long [%s]\n", strBuff);
        return 1;
    }

    printf ("OK [%s]\n", strBuff);

    numScanned = sscanf (strBuff, "%d %d %[^\n]", &int1, &int2, str1);
    printf ("numScanned = %d\n", numScanned);
    printf ("int1       = %d\n", int1);
    printf ("int2       = %d\n", int2);
    printf ("str1       = [%s]\n", str1);

    return 0;
}

次の出力が得られます。

Yes> 100 20 300 20 9 45 -1 blah blah blah
OK [100 20 300 20 9 45 -1 blah blah blah]
numScanned = 3
int1       = 100
int2       = 20
str1       = [300 20 9 45 -1 blah blah blah]

(a)7.20.6.2 The fscanf functionのセクションC11(これはから変更されていませんがC99)は、フォーマット指定子についてこれを述べてい[ますが、無関係なマルチバイトのものを削除するために少し言い換えられています:

[フォーマット指定子は、予期される文字のセット(スキャンセット)からの空でない文字のシーケンスと一致します。

対応する引数は、シーケンスを受け入れるのに十分な大きさの文字配列の初期要素へのポインタと、自動的に追加される終了ヌル文字でなければなりません。

変換指定子には、一致する右角かっこ()までの、フォーマット文字列内の後続のすべての文字が含まれます]

左角かっこの後の文字が曲折アクセント記号(^)でない限り、角かっこ(スキャンリスト)の間の文字がスキャンセットを構成します。この場合、スキャンセットには、曲折アクセント記号と右角かっこの間のスキャンリストに表示されないすべての文字が含まれます。[]変換指定子がまたはで始まる場合、[^]右角かっこ文字はスキャンリストにあり、次の右角かっこ文字は、指定を終了する一致する右角かっこです。それ以外の場合、最初に続く右角かっこは仕様を終了する文字です。

于 2012-10-23T01:21:21.087 に答える
4

いや、scanfバッファのサイズがわかっていれば使用できます。バッファオーバーフローを回避し、それがいつ発生したかをテストできます。リカバリロジックは物事を台無しにしますが、それでも可能です。オーバーフローが実際にギブアップアンドダイの種類のエラーになるように、バッファを十分に大きくすることをお勧めします。

まず、256バイのバッファと、宣言する必要のある他のいくつかの変数を想定します。保存できる最長の文字列は255バイトです。\n内部の空白をスキャンしたいが、最後の改行を文字列の一部にしたくない場合があります。(この場合、これがの主な問題fgetsです。)魔法のシーケンスは次のとおりです。

char var[256], endchar = '\n';
int n;

n = scanf("%255[^\n]%c", var, &endchar);
if ((n < 1) || (endchar!='\n') || ferror(stdin))
{
    if (n==2) { /*it's a buffer overflow*/ }
    else if (n==0 && !ferror(stdin)) { /*must be EOF on 1st byte*/ }
    else { /*an I/O error occurred*/ }
} else { /* OK */ }

これはほとんど防弾であり、すべてのループはライブラリで発生します。scanf形式は次のように分類されます。

  1. %255[^\n]:改行以外の最大255の文字列。
  2. %c:次の文字があれば、それを格納する単一の文字。

戻り値は、正常に格納されたフィールドの数です。つまり、の終了値endcharferror()結果は、いくつかのifステートメントで知っておく必要のあるすべてのことを示しています。シングルifは通常のケースを検出します。

これによりEOF、最後の行に改行を入れなくてもかまいません。その場合、feof(stdin)は、外側のループが検出する場合に当てはまります。

PS:に対するscanf %s(および関連する%[])引数は十分に根拠が%nnnsありますが、値がバッファーサイズと一致する%nnn[]ことを確認できれば、完全に安全です。"nnn"残念ながら、フォーマットに計算バッファサイズを提供する方法はありません。私が知っている最良のオプションは、でscanf()フォーマットを動的に生成することですsprintf()

于 2012-10-23T02:08:01.670 に答える