C语言 发生错误时While循环未中断

ovfsdjhp  于 2023-01-12  发布在  其他
关注(0)|答案(3)|浏览(121)

下面的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);

我试着做一个循环,如果错误地添加了一个字母,它就会循环。

velaa5lx

velaa5lx1#

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);
oxosxuxt

oxosxuxt2#

在尝试扫描float之后,扫描并丢弃除换行符之外的空白,扫描丢弃并计数任何剩余的非换行符字符,扫描换行符。
%n说明符将提供扫描处理的字符计数,直到该说明符为止。
扫描集%*[ \t\f\v]中的星号指示scanf丢弃匹配字符。扫描集%*[^\n]中的插入符号指示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;
}
sg24os4d

sg24os4d3#

在尝试使用结果之前,应始终检查scanf的返回值,以确定输入是否已成功转换。
但是,对于基于行的用户输入,使用函数scanf通常是不可取的,因为它的行为不直观,它通常不消耗整行输入,这会引起各种各样的麻烦,例如scanf在输入流上留下换行符会引起this问题,如果用户输入6abc\n,那么情况就更糟了:在这种情况下,scanf将匹配6作为有效输入,但将abc\n保留在输入流中,这很可能导致下一个输入操作无法按预期运行,除非您事先从输入流中显式丢弃该行的剩余部分。
由于上述原因,通常最好总是一次将整行输入作为字符串读取,例如使用函数fgets,然后可以使用函数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

我在上面的代码中使用的函数get_float_from_user是基于this answer of mine to another question中的函数get_int_from_user的,关于该函数如何工作的进一步解释,请参见上面的答案。

相关问题