2012-02-26 11 views
8

まず、sscanfの使用に関する他の質問は私の質問には答えません。よくある答えはsscanfを使用せず、代わりにfgetsまたはgetchを使用します。これは私の場合は不可能です。sscanfを正しく安全に使用する方法

問題は私のC教授が私にプログラムでscanfを使用したかったことです。それは要件です。 しかし、プログラムはまた、すべての誤った入力を処理しなければなりません。

プログラムは整数の配列を読み取る必要があります。アレイの整数 がどのフォーマットで供給されるかは重要ではありません。タスクを簡単にするために、プログラムは最初に配列のサイズを読み込み、次に整数を新しい行に読み込みます。

プログラムは、このような入力を扱う(そして適切にエラーを報告する)必要があります。

  1. 999999999999999 ... 9(数字整数より大きい)を
  2. 12A3(整数12としてこれを読んでいません)
  3. ... Z(ストリング)
  4. 11 AA 22 33 \ n個の入力アレイ
  5. より大きい1つのラインの全て(これは11の後にすべてを捨てることによって処理されるかもしれない)
  6. 入力

もっと誤ったケースがあるかもしれませんが、これらは私が考えることができる唯一のものです。誤入力が供給されている場合は

、プログラムは正しい入力が与えられるが、前回の正しい入力が保たれなければならない(唯一間違った 入力が入力ストリームからクリアする必要があります) まで再入力をユーザーに依頼する必要があります。

すべてがC99規格に準拠している必要があります。

答えて

10

を受け入れましょう機能のscanf家族は、整数を扱う場合は特に、安全に使用することはできません。あなたが言及した最初のケ​​ースは特に面倒です。このオブジェクトが適切な型を持っていない、または 変換の結果は、オブジェクトで表現できない場合、動作は定義さ アンクルFiありの場合

:標準はこれを言います。

プレーンでシンプルです。 %5dのようなトリックだと思うかもしれませんが、信頼できるものではありません。あるいは、誰かがerrnoを考えるかもしれない。 scanfファンクションは設定する必要はありませんerrnoです。

これに続いてfun little page:これらは完全にscanfになります。


だからあなたのC教授に戻って、彼に尋ねるこの:がどのように正確sscanf関数がエラーをC99の任務報告しますないこと

+1

技術的には、上記の要件を満たすことが条件です。 scanfは固定サイズの文字列に整形されており、それをチェックし、sscanfは(今度は確かに有効な)変換を行います。ちょっとばかげていますが、それは破損することなくscanfを使用するという要件を満たしています。 – davenpcj

1

まあ、sscanf関数は、すべて%sの入力として(すなわち文字列)と、プログラムはそれらを分析

+0

'scanf'の'%s'は潜在的なバッファオーバーフローです。 – ThiefMaster

+2

@ThiefMaster:宛先がソースより大きい限り、はい、必ずしも 'sscanf'にあるとは限りません。一方、 '%s'は空白で区切られた単語であり、文字列全体ではありません。 –

+0

@ThiefMaster "%100s"(例:100文字制限)のようなフィールド幅を使用すると、オーバーフローを避けることができます。 – davenpcj

1

入力を受け入れるにはscanfを使用する必要がある場合、次のようなものから始めてください。

int array[MAX]; 
int i, n; 
scanf("%d", &n); 
for (i = 0; i < n && !feof(stdin); i++) { 
    scanf("%d", &array[i]); 
} 

%d形式に一致するときscanfが自動的に先頭の空白をスキップするので、これは自由形式の入力の問題(多かれ少なかれ)を処理します。

残りの多くの懸案事項の重要な点は、scanfは、どのように多くのフォーマットコードが正常に解析されたかを伝えることです。だから、

int matches = scanf("%d", &array[i]); 
if (matches == 0) { 
    /* no integer in the input stream */ 
} 

私は、これはそれ自体で直接懸念(3)と(4)

を処理し、これはかなり入力12a3のケースを処理しませんと思います。ループを初めて通過するとき、scanfは次のループのために'12 as an integer 12, leaving the remaining a3`を解析する。あなたは次回のラウンドでエラーになるでしょう。あなたの教授の目的には十分ですか? MAXINTより大きい整数、例えば、「999999 ....... 999」については

、私はあなたがまっすぐscanfで何ができるかわかりません。入力配列より大きい入力について

、これはscanf問題自体ありません。今まで解析した整数の数を数えてみるだけです。

while (...) { 
    scanf("%s", buf); 
    /* use strtol or sscanf if you really have to */ 
} 

これは、任意の順序のために動作します:彼らはあなたもこのような何かを行うことができscanf("%s")のようなもので、入力ストリームから抽出してきた後、あなたが文字列をデコードするsscanfの使用を許可している場合

空白で区切られた単語を使用して、単語の入力をスキャンし、単語が数字のように見えるかどうかを確認することができます。また、必要な場合は、各部品にscanfのバリエーションを使用することができます。

+0

getchar()の代わりにscanf( '%c'、c)を使うのはどうですか?それは安全であり、要件を満たすだろうか? – evodevo

+0

真ですが、 'scanf("%c "、&c)'はgetchar()をエミュレートするための高価な方法です。代入は本当にこの種のシンタックス上の 'scanf'の使用についてですか?私は@ cnicutarのコメントは本当に中心的な問題であると考えています。標準の抜粋を引用すると、 'scanf'を使ってオーバーフローしているintergerの入力を安全に解析することは不可能です。 –

+0

@evodevo: 'scanf( '%c'、c)'は、書式文字列が一般的にC++では避けられるべき理由の良い例です。あまりにも悪いコメントをブックマークすることはできません:D –

関連する問題