虽然通常不建议使用scanf
进行基于行的用户输入,但我将首先介绍一种使用scanf
的解决方案。
这个解决方案通过检查未被scanf
消耗的行上剩余字符来工作。通常,这应该只是换行符。然而,由于使用scanf
的%d
格式说明符接受前导空格字符,如果程序也接受尾随空格字符,则会更加一致。
这是我的使用scanf
的解决方案:
#include <stdio.h>
#include <ctype.h>
int main( void )
{
int n;
for (;;)
{
int c;
printf( "Please enter an integer: " );
if ( scanf( "%d", &n ) == 1 )
{
while ( ( c = getchar() ) != EOF && c != '\n' )
{
if ( !isspace(c) )
{
goto invalid_input;
}
}
break;
}
invalid_input:
printf( "Input is invalid!\n" );
do
{
c = getchar();
} while ( c != EOF && c != '\n' );
}
printf("You entered: %d\n",n);
return 0;
}
这个程序具有以下行为:
Please enter an integer: abc
Input is invalid!
Please enter an integer: 6abc
Input is invalid!
Please enter an integer: 6.7
Input is invalid!
Please enter an integer: 6
You entered: 6
这个 scanf
解决方案存在以下问题:
- 如果用户输入的数字无法表示为
int
(例如大于 INT_MAX
的数字),程序将会出现 未定义行为。
- 如果用户输入空行,它不会打印错误消息。这是因为
scanf
的 %d
格式化符号会消耗所有前导空格字符。
可以通过使用函数 fgets
和 strtol
来解决这两个问题,而不是使用函数 scanf
。
执行所有这些验证检查会使代码变得相当庞大。因此,将所有代码放入自己的函数中是有意义的。以下是一个示例,它使用了我从
我的另一个问题的答案中提取的函数
get_int_from_user
:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
int get_int_from_user( const char *prompt );
int main( void )
{
int number;
number = get_int_from_user( "Please enter an integer: " );
printf( "Input was valid.\n" );
printf( "The number is: %d\n", number );
return 0;
}
int get_int_from_user( const char *prompt )
{
for (;;)
{
char buffer[1024], *p;
long l;
fputs( prompt, stdout );
if ( fgets( buffer, sizeof buffer, stdin ) == NULL )
{
fprintf( stderr, "Unrecoverable input error!\n" );
exit( EXIT_FAILURE );
}
if ( strchr( buffer, '\n' ) == NULL && !feof( stdin ) )
{
int c;
printf( "Line input was too long!\n" );
do
{
c = getchar();
if ( c == EOF )
{
fprintf( stderr, "Unrecoverable error reading from input!\n" );
exit( EXIT_FAILURE );
}
} while ( c != '\n' );
continue;
}
errno = 0;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
printf( "Number out of range error!\n" );
continue;
}
for ( ; *p != '\0'; p++ )
{
if ( !isspace( (unsigned char)*p ) )
{
printf( "Unexpected input encountered!\n" );
goto continue_outer_loop;
}
}
return l;
continue_outer_loop:
continue;
}
}
这个程序具有以下行为:
Please enter an integer: abc
Error converting string to number!
Please enter an integer: 6abc
Unexpected input encountered!
Please enter an integer: 6.7
Unexpected input encountered!
Please enter an integer: 6000000000
Number out of range error!
Please enter an integer: 6
Input was valid.
The number is: 6
scanf
来实现吗?我们总是要使用fgets
吗? - ani627scanf()
完成,但在一般情况下,scanf()
是可怕且不安全的。 - The Paramagnetic Croissantfgets
和strtol
来完成这个任务,但我想知道是否可以使用scanf()
来实现。 - ani627