簡體   English   中英

當發生錯誤時,While Loop 不會中斷

[英]While Loop doesn't break when error occurrs

添加字母時,下面的 while 循環會中斷。 我希望它繼續循環,即使添加了一個字母,以及添加了一個負數。 這是我當前的代碼:

float monthpay;

printf("Please enter your monthly wage:\t");
    scanf("%f", &monthpay);
    while (monthpay <= 0)
    {
        printf("\nThat was invalid");
        printf("\n Please try again: ");
        scanf("%f", &monthpay);

    }
printf("%.2f", monthpay);

我試圖制作一個循環,如果錯誤地添加了一個字母,它就會循環。

scanf()返回成功匹配和分配的輸入項數。 如果您不檢查返回值 ( rv ),您的變量 ( monthpay ) 可能未初始化,使用它是未定義的行為。

void flush() {
   for(;;) {
     char ch;
     int rv = scanf("%c", &ch);
     if(rv == EOF || rv == 1 && ch == '\n') return;
   }
}

printf("Please enter your monthly wage:\t");
float monthpay;
for(;;) {
    int rv = scanf("%f", &monthpay);
    if(rv == EOF)
        return;
    if(rv == 1)
        break;
    printf("\nThat was invalid");
    printf("\n Please try again: ");
    flush();
}
printf("%.2f", monthpay);

在嘗試使用結果之前,您應該始終檢查scanf的返回值以確定輸入是否已成功轉換。

但是,對於基於行的用戶輸入,通常不建議使用 function scanf ,因為它的行為不直觀。 它通常不會消耗整行輸入,這會導致各種麻煩。 例如, scanf在輸入 stream 上留下換行符可能會導致問題。 如果用戶輸入6abc\n ,那么情況更糟:在這種情況下, scanf會將6匹配為有效輸入,但將abc\n保留在輸入 stream 上,這很可能導致下一個輸入操作無法正常運行按照預期,除非您事先明確丟棄輸入 stream 中該行的其余部分。

出於上述原因,通常最好始終將整行輸入作為字符串一次讀取,例如使用 function fgets 然后,您可以使用 function strtof嘗試將字符串轉換為數字。

這是一個示例,它執行廣泛的輸入驗證:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>

float get_float_from_user( const char *prompt );

int main( void )
{
    float monthpay;

    //loop forever until user enters a valid number
    for (;;) //infinite loop, equivalent to while(1)
    {
        monthpay = get_float_from_user( "Please enter your monthly wage: ");
        if ( monthpay > 0 )
        {
            //input is ok, so we can break out of the loop
            break;
        }

        printf( "Please enter a positive number!\n" );
    }

    printf( "Input was valid. You entered: %.2f\n", monthpay );

    return 0;
}

float get_float_from_user( const char *prompt )
{
    //loop forever until user enters a valid number
    for (;;)
    {
        char buffer[1024], *p;
        float f;

        //prompt user for input
        fputs( prompt, stdout );

        //get one line of input from input stream
        if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
        {
            fprintf( stderr, "Unrecoverable input error!\n" );
            exit( EXIT_FAILURE );
        }

        //make sure that entire line was read in (i.e. that
        //the buffer was not too small)
        if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
        {
            int c;

            printf( "Line input was too long!\n" );

            //discard remainder of line
            do
            {
                c = getchar();

                if ( c == EOF )
                {
                    fprintf( stderr, "Unrecoverable error reading from input!\n" );
                    exit( EXIT_FAILURE );
                }

            } while ( c != '\n' );

            continue;
        }

        //attempt to convert string to number
        errno = 0;
        f = strtof( buffer, &p );
        if ( p == buffer )
        {
            printf( "Error converting string to number!\n" );
            continue;
        }

        //make sure that number is representable as a "float"
        if ( errno == ERANGE )
        {
            printf( "Number out of range error!\n" );
            continue;
        }

        //make sure that remainder of line contains only whitespace,
        //so that input such as "6abc" gets rejected
        for ( ; *p != '\0'; p++ )
        {
            if ( !isspace( (unsigned char)*p ) )
            {
                printf( "Unexpected input encountered!\n" );

                //cannot use `continue` here, because that would go to
                //the next iteration of the innermost loop, but we
                //want to go to the next iteration of the outer loop
                goto continue_outer_loop;
            }
        }

        return f;

    continue_outer_loop:
        continue;
    }
}

該程序具有以下行為:

Please enter your monthly wage: abc
Error converting string to number!
Please enter your monthly wage: 6abc
Unexpected input encountered!
Please enter your monthly wage: 6e+2000
Number out of range error!
Please enter your monthly wage: -5
Please enter a positive number!
Please enter your monthly wage: 0
Please enter a positive number!
Please enter your monthly wage: 6.3
Input was valid. You entered: 6.30

我在上面的代碼中使用的 function get_float_from_user是基於 function get_int_from_user from this answer of mine to another question 有關 function 如何工作的進一步解釋,請參閱該答案。

在嘗試掃描float之后,掃描並丟棄換行符以外的空格,掃描丟棄並計算所有剩余的不是換行符的字符,然后掃描換行符。
%n說明符將提供掃描處理的字符數,直到說明符為止。
掃描集中的星號%*[ \t\f\v]告訴 scanf 丟棄匹配的字符。 scanset %*[^\n]中的 carat 告訴 scanf 處理不匹配的字符,以便丟棄所有不是換行符的字符。 %1[\n]告訴 scanf 掃描一個字符,它必須是換行符。 如果輸入一個浮點數后僅跟有空格,則循環將退出,因為scanned將為 2, extra將為 0。

#include <stdio.h>

int main ( void) {
    char newline[2] = "";
    int extra = 0;
    int scanned = 0;
    float monthpay = 0.0;

    do {
        printf ( "enter monthly pay\n");
        scanned = scanf ( "%f", &monthpay);
        if ( scanned == EOF) {
            return 1;
        }
        extra = 0;
        scanf ( "%*[ \f\t\v]"); // scan and discard whitespace except newline
        scanf ( "%*[^\n]%n", &extra); // scan discard and count non-whitespace
        scanned += scanf ( "%1[\n]", newline);
    } while ( monthpay < 0 || scanned != 2 || extra != 0);

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM