これがあなたが最初にすることです。入力データを完全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
)は、フォーマット指定子についてこれを述べてい[
ますが、無関係なマルチバイトのものを削除するために少し言い換えられています:
[
フォーマット指定子は、予期される文字のセット(スキャンセット)からの空でない文字のシーケンスと一致します。
対応する引数は、シーケンスを受け入れるのに十分な大きさの文字配列の初期要素へのポインタと、自動的に追加される終了ヌル文字でなければなりません。
変換指定子には、一致する右角かっこ()までの、フォーマット文字列内の後続のすべての文字が含まれます]
。
左角かっこの後の文字が曲折アクセント記号(^)でない限り、角かっこ(スキャンリスト)の間の文字がスキャンセットを構成します。この場合、スキャンセットには、曲折アクセント記号と右角かっこの間のスキャンリストに表示されないすべての文字が含まれます。[]
変換指定子がまたはで始まる場合、[^]
右角かっこ文字はスキャンリストにあり、次の右角かっこ文字は、指定を終了する一致する右角かっこです。それ以外の場合、最初に続く右角かっこは仕様を終了する文字です。