5

.txt ファイルを読み込んでいます。fscanf を使用して、フォーマットされたデータを取得しています。私が問題を抱えている行はこれです:

result = fscanf(fp, "%s", ap->name);

これは、名前に空白が含まれるまでは問題ありません。たとえば、St Ives という名前を使用します。

result = fscanf(fp, "%[^\n]s", ap->name);

ただし、最初の名前 (空白なし) を読み取ろうとすると、機能せず、他の fscanf が台無しになります。

しかし、私は使用している別のファイル内で [^\n] を使用しています。何が起こっているのかわからない。

上記の fscanf の代わりに fgets を使用すると、変数に "\n" が入ります。

編集//

わかりましたので、私が使用する場合:

result = fscanf(fp, "%s", ap->name);
result = fscanf(fp, "%[^\n]s", ap->name);

これにより、空白のない文字列を読み取ることができます。しかし、空白を含む「名前」を取得すると機能しません。

4

5 に答える 5

13

これに関する1つの問題:

result = fscanf(fp, "%[^\n]s", ap->name);

sフォーマット指定子の最後に余分なものがあるということです。%[^\n]フォーマット指定子全体は、「改行ではない文字で構成される文字列を読み取る」というだけのはずです。エクストラsはフォーマット指定子の一部ではないため、リテラルとして解釈されます。「入力から次の文字を読み取ります。「s」の場合は続行し、それ以外の場合は失敗します。」

ただし、余分なsものは実際にはあなたを傷つけません。入力の次の文字である改行が正確にわかります。一致せず、入力処理はそこで停止しますが、書式指定子の最後なので問題ありません。ただし、同じフォーマット文字列でこの後に他のフォーマット指定子がある場合、これは問題を引き起こします。

本当の問題は、改行を消費していないことです。改行までのすべての文字を読み取っているだけで、改行自体は読み取っていません。これを修正するには、次のようにする必要があります。

result = fscanf(fp, "%[^\n]%*c", ap->name);

%*c指定子は、文字 ( ) を読み取るように指示していcますが、それを変数に代入しないでください ( *)。を省略した場合は、文字 (a) へのポインターを含む別のパラメーターを*渡す必要があり、そこで読み取った結果の文字を格納します。fscanf()char*

を使用することもでき%[^\n]\nますが、改行に続く空白も読み取られます。これは、必要なものではない可能性があります。がfscanf書式指定子 (スペース、改行、またはタブ) に空白を見つけると、できるだけ多くの空白を消費します (つまり、正規表現に一致する最長の文字列を消費すると考えることができます[ \t\n]*)。

最後に、バッファ オーバーランを回避するために、最大長も指定する必要があります。%これを行うには、と の間にバッファー長を配置し[ます。たとえば、ap->nameが 256 文字のバッファの場合、次のようにする必要があります。

result = fscanf(fp, "%255[^\n]%*c", ap->name);

これは、静的に割り当てられた配列に最適です。残念ながら、配列が実行時に動的にサイズ設定されている場合、バッファ サイズを に渡す簡単な方法はありませんfscanfsprintfたとえば、次のようにフォーマット文字列を作成する必要があります。

char format[256];
snprintf(format, sizeof(format), "%%%d[^\n]%%*c", buffer_size - 1);
result = fscanf(fp, format, ap->name);
于 2009-12-12T16:03:19.250 に答える
2

ジャムは書いた:

上記のfscanfの代わりにfgetsを使用すると、変数に「\n」が含まれます。

これは解決するのがはるかに簡単な問題なので、それに従ってください:

fgets( ap->name, MAX, fp ) ;
nlptr = strrchr ( ap->name, '\n' ) ;
if( nlptr != 0 )
{
    *nlptr = '\0' ;
}
于 2009-12-12T14:58:37.933 に答える
0

私が収集するようなものはありません。あなたがfscanf存在しない関数の正規表現を暗示しようとしているのは、私の知る限りではなく、どこにも見たことがありません。これについて私に教えてください。

文字列を読み取るためのフォーマット指定子はです。%sこの方法でそれを行う必要がある可能性があり%s\nます。これにより、改行が取得されます。

しかし、ピートのために、上記のクリフォードの回答で指定されてgetsいる標準の古いファミリ関数を使用しないでください。バッファオーバーフローが発生し、1990年代の悪名高いワームで使用されていました。それは混乱を引き起こしました。幸いなことに、今、それはパッチされています。さらに、多くのプログラマーは、この関数を使用しないという考え方を掘り下げてきました。fingerdgets

Microsoftでさえ、安全なバージョンのgets関数ファミリーを採用しており、代わりにバッファーの長さを示すパラメーターを指定しています。

編集 私の悪い-クリフォードが実際に入力の最大長を指定していることに気づいていませんでした...おっと!ごめん!クリフォードの答えは正しいです!したがって、クリフォードの答えに+1します。

私のエラーを指摘してくれたニールに感謝します...

これがお役に立てば幸いです、よろしく、トム。

于 2009-12-12T15:09:33.950 に答える
0

[^\n]がうまくいくとはどういう意味かわかりません。[]は、「このブロック内にある文字を除く1文字を受け入れる」という修飾子です。^状態を反転します。fscanfを使用した%sは、区切り文字に遭遇するまでのみ読み取ります。スペースと改行が含まれる文字列の場合は、代わりにfgetsとsscanfの組み合わせを使用し、長さの制限を指定します。

于 2009-12-12T14:55:21.950 に答える
-1

問題を見つけました。

Paul Tomblinが言ったように、上のフィールドに新しい改行文字が追加されました。したがって、tommieb75が私が使用したと言ったことを使用します。

result = fscanf(fp, "%s\n", ap->code);
result = fscanf(fp, "%[^\n]s", ap->name);

そしてこれはそれを修正しました!

ご協力いただきありがとうございます。

于 2009-12-12T15:43:17.220 に答える