ループサイクルごとに1つずつ、標準入力から数値を読み取る小さなCプログラムがあります。ユーザーがNaNを入力すると、エラーがコンソールに出力され、入力プロンプトが再び返されます。 「0」を入力すると、ループが終了し、指定された正/負の値の数がコンソールに出力されます。プログラムは次のとおりです。
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
私の問題は、「a」などの非数値を入力すると、「-> Err ...」を何度も繰り返し記述する無限ループになることです。 scanf()の問題だと思いますが、この関数はより安全なものに置き換えることができますが、この例は初心者向けで、printf/scanf、if-else、loopについて知っています。
この質問 への回答を読んで、他の質問をざっと読みましたが、この特定の問題に実際に答えているものはありません。
scanf
は、フォーマット文字列に一致する入力のみを消費し、消費された文字数を返します。フォーマット文字列と一致しない文字があると、スキャンが停止し、無効な文字がバッファに残ったままになります。他の人が言ったように、続行する前に、バッファから無効な文字をフラッシュする必要があります。これはかなり汚い修正ですが、出力から問題のある文字を削除します。
char c = '0';
if (scanf("%d", &number) == 0) {
printf("Err. . .\n");
do {
c = getchar();
}
while (!isdigit(c));
ungetc(c, stdin);
//consume non-numeric chars from buffer
}
edit:すべての非数値文字を一度に削除するようにコードを修正しました。数値ではない文字ごとに複数の「Err」を出力しなくなりました。
ここ はscanfの概要です。
ループを続行する前にバッファをフラッシュする必要があると思います。私はここから書いているものをテストすることはできませんが、そのような何かがおそらく仕事をするでしょう:
int c;
while((c = getchar()) != '\n' && c != EOF);
同様の問題がありました。 scanfのみを使用して解決しました。
Input "abc123<Enter>"
仕組みを確認します。
#include <stdio.h>
int n, num_ok;
char c;
main() {
while (1) {
printf("Input Number: ");
num_ok = scanf("%d", &n);
if (num_ok != 1) {
scanf("%c", &c);
printf("That wasn't a number: %c\n", c);
} else {
printf("The number is: %d\n", n);
}
}
}
他の回答で指摘されたscanf
の問題のため、別のアプローチを検討する必要があります。 scanf
の方法は、深刻な入力の読み取りと処理には制限が多すぎることを常に認識しています。 fgets
を使用して行全体を読み取り、strtok
やstrtol
(BTWが整数を正しく解析して正確な場所を正確に伝える)などの関数を使用して作業することをお勧めします無効な文字が始まります)。
一部のプラットフォーム(特にWindowsおよびLinux)では、fflush(stdin);
を使用できます。
#include <stdio.h>
int main(void)
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fflush(stdin);
printf("Err...\n");
continue;
}
fflush(stdin);
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
scanf()
を使用して無効な文字を持つバッファーを処理する必要があるのではなく、fgets()
とsscanf()
を使用します。
/* ... */
printf("0 to quit -> ");
fflush(stdout);
while (fgets(buf, sizeof buf, stdin)) {
if (sscanf(buf, "%d", &number) != 1) {
fprintf(stderr, "Err...\n");
} else {
work(number);
}
printf("0 to quit -> ");
fflush(stdout);
}
/* ... */
解決策:fflush(stdin);
を追加する必要があるとき0
はscanf
から返されます。
理由:エラーが発生するとバッファに入力文字が残っているように見えるため、scanf
が呼び出されるたびに無効な文字を処理しようとし続けますが、削除はしません。バッファを形成します。 fflush
を呼び出すと、入力バッファ(stdin)がクリアされるため、無効な文字は繰り返し処理されなくなります。
You Program Modified:以下は、必要な変更でプログラムを修正したものです。
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fflush(stdin);
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
問題を部分的に解決するために、scanfの後に次の行を追加します。
fgetc(stdin); /* to delete '\n' character */
以下に、次の行を含むコード:
#include <stdio.h>
int main()
{
int number, p = 0, n = 0;
while (1) {
printf("-> ");
if (scanf("%d", &number) == 0) {
fgetc(stdin); /* to delete '\n' character */
printf("Err...\n");
continue;
}
if (number > 0) p++;
else if (number < 0) n++;
else break; /* 0 given */
}
printf("Read %d positive and %d negative numbers\n", p, n);
return 0;
}
ただし、複数の文字を入力すると、プログラムは「\ n」まで1文字ずつ続けます。
だから私はここで解決策を見つけました: scanfで入力長を制限する方法
次の行を使用できます。
int c;
while ((c = fgetc(stdin)) != '\n' && c != EOF);
数字以外を入力するとエラーが発生し、数字以外は入力バッファに保持されます。スキップしてください。また、たとえば1a
は最初は1番として読み込まれます。このような入力もスキップする必要があると思います。
プログラムは次のようになります。
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int p = 0, n = 0;
while (1)
{
char c;
int number;
int success;
printf("-> ");
success = scanf("%d%c", &number, &c);
if ( success != EOF )
{
success = success == 2 && isspace( ( unsigned char )c );
}
if ( ( success == EOF ) || ( success && number == 0 ) ) break;
if ( !success )
{
scanf("%*[^ \t\n]");
clearerr(stdin);
}
else if ( number > 0 )
{
++p;
}
else if ( number < n )
{
++n;
}
}
printf( "\nRead %d positive and %d negative numbers\n", p, n );
return 0;
}
プログラムの出力は次のようになります
-> 1
-> -1
-> 2
-> -2
-> 0a
-> -0a
-> a0
-> -a0
-> 3
-> -3
-> 0
Read 3 positive and 3 negative numbers
私は同じ 問題 を持っていて、ややハックな解決策を見つけました。 fgets()
を使用して入力を読み取り、それをsscanf()
にフィードします。これは、無限ループの問題に対する悪い修正ではなく、単純なforループを使用して、数字以外の文字を検索するようにCに指示します。以下のコードは、123abc
のような入力を許可しません。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, const char * argv[]) {
char line[10];
int loop, arrayLength, number, nan;
arrayLength = sizeof(line) / sizeof(char);
do {
nan = 0;
printf("Please enter a number:\n");
fgets(line, arrayLength, stdin);
for(loop = 0; loop < arrayLength; loop++) { // search for any none numeric charcter inisde the line array
if(line[loop] == '\n') { // stop the search if there is a carrage return
break;
}
if((line[0] == '-' || line[0] == '+') && loop == 0) { // Exculude the sign charcters infront of numbers so the program can accept both negative and positive numbers
continue;
}
if(!isdigit(line[loop])) { // if there is a none numeric character then add one to nan and break the loop
nan++;
break;
}
}
} while(nan || strlen(line) == 1); // check if there is any NaN or the user has just hit enter
sscanf(line, "%d", &number);
printf("You enterd number %d\n", number);
return 0;
}
これを使ってみてください:
if (scanf("%d", &number) == 0) {
printf("Err...\n");
break;
}
これは私のためにうまくいきました...これを試してください。continueステートメントはErr。 1回だけ実行する必要があります。だから、試してみてくださいbreakこれはあなたのためにうまくいきました..私はテストしました....