c语言 - 如何不将 1.0 计为整数



所以我需要从用户可能输入 1.0 的 stdin 中读取一个整数,但是由于这是一个双精度,我不想接受它。但是,当我尝试以下的方法时,1.0 将转换为 1 并被接受。我还想接受 0001 作为可能的整数输入为 1。

first_sentence_to_switch = 0;
char buf[15]; // large enough
int number;
wrong_input = 0;
scanf("%14s", buf); // read everything we have in stdin
// printf("buffer: %s", buf);
if (sscanf(buf, "%d", &number) == 1)
{
first_sentence_to_switch = number;
}
else
{
wrong_input = 1;
}

您可以使用 %n 格式选项来判断与 sscanf 调用匹配了多少,以确保行上没有多余的问题:

if (sscanf(buf, "%d %n", &number, &end) == 1 && buf[end] == 0) {
.. ok
} else {
.. not an integer or something else in the input (besides whitespace) after the integer

请注意%d%n之间的空格,以跳过缓冲区末尾可能存在的任何空格(例如,如果输入由 fgets 或 getline 读取,则使用换行符)

如何读取整行输入

该行

scanf("%14s", buf);

永远不会读取整行输入。它只会读取一个输入单词(也可以由数字组成)。例如,如果用户输入无效的输入,例如

"39 jdsuoew"

在一行上,则它只会将单词"39"读取为输入,而将行的其余部分留在输入流上。这意味着您的程序将接受有效的输入,尽管在这种情况下可能应该拒绝它。

即使用户只输入了"39",那么它也只会读取这个数字,但会在输入流上留下换行符,这可能会导致麻烦。

如果要确保它读取整行,我建议您改用函数fgets,因为该函数将始终读取整行输入(包括换行符),假设提供的内存缓冲区的大小足以存储整行。

char line[100];
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Input error!n" );
exit( EXIT_FAILURE );
}
//search for newline character, to verify that entire line was read in
if ( strchr( line, 'n' ) == NULL )
{
fprintf( stderr, "Line was too long for input buffer!n" );
exit( EXIT_FAILURE );
}

请注意,该函数strchr要求您#include <string.h>。如果如您在注释部分所述,不允许使用该头文件,那么您可能不得不假设内存缓冲区对于整行来说足够大,而无需对其进行验证(您在代码中也这样做)。虽然可以在不使用函数的情况下验证这一点strchr,我不建议这样做。如果缓冲区足够大,则行不太可能(但仍有可能)不适合缓冲区。

使用strtol将字符串转换为整数

将输入行读入内存缓冲区后,可以使用函数sscanfstrtol尝试将整数转换为数字。我建议您使用函数strtol,因为如果用户输入的数字太大而无法表示为long int,则函数sscanf具有未定义的行为,而函数strtol能够可靠地报告此类错误条件。

为了将读取的行转换为整数,您可以简单地调用strtol如下:

long l;
l = strtol( line, NULL, 10 );

但是,在第二个参数设置为NULL的情况下调用函数与调用函数atoi具有相同的问题:您无法知道输入是否已成功转换,或者是否发生了转换错误。而且,您也无法知道有多少输入成功转换,以及转换是否过早失败,例如由于用户输入浮点数的小数点。

因此,最好像这样调用该函数:

long l;
char *p;
l = strtol( line, &p, 10 );

现在,指针p将指向第一个未成功转换为数字的字符。在理想情况下,它将指向行尾的换行符(或者如果您不使用fgets,则指向终止空字符)。因此,您可以验证整行是否已转换,并且至少转换了一个字符,如下所示:

if ( p == line || *p != 'n' )
{
printf( "Error converting number!n" );
exit( EXIT_FAILURE );
}

但是,这可能有点过于严格。例如,如果用户输入"39 "(数字后有一个空格),则输入将被拒绝。在这种情况下,您可能希望接受输入。因此,您可能希望允许空格字符保留在行中,而不是要求p指向换行符,从而不接受该行上的任何其他剩余字符,如下所示:

if ( p == line )
{
printf( "Error converting number!n" );
exit( EXIT_FAILURE );
}
while ( *p != 'n' )
{
//verify that remaining character is whitespace character
if ( !isspace( (unsigned char)*p ) )
{
printf( "Error converting number!n" );
exit( EXIT_FAILURE );
}
p++;
}

请注意,您必须#include <ctype.h>才能使用函数isspace

此外,如前所述,使用函数strtol优于sscanf的优点是它可以可靠地报告数字是太大还是太小而无法表示为long int。如果发生此类错误情况,它将errno设置为ERANGE。请注意,您必须#include <errno.h>才能使用errno

long l;
char *p;
errno = 0; //make sure that errno is not already set to ERANGE
l = strtol( line, &p, 10 );
if ( errno == ERANGE )
{
printf( "Number out of range!n" );
exit( EXIT_FAILURE );
}

fgetsstrtol的代码示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
int main( void )
{
char line[100], *p;
long l;
//prompt user for input
printf( "Please enter an integer: " );
//attempt to read one line of input
if ( fgets( line, sizeof line, stdin ) == NULL )
{
fprintf( stderr, "Input error!n" );
exit( EXIT_FAILURE );
}
//search for newline character, to verify that entire line was read in
if ( strchr( line, 'n' ) == NULL )
{
fprintf( stderr, "Line was too long for input buffer!n" );
exit( EXIT_FAILURE );
}
//make sure that errno is not already set to ERANGE
errno = 0;
//attempt to convert input to integer
l = strtol( line, &p, 10 );
//verify that conversion was successful
if ( p == line )
{
printf( "Error converting number!n" );
exit( EXIT_FAILURE );
}
//check for range error
if ( errno == ERANGE )
{
printf( "Number out of range!n" );
exit( EXIT_FAILURE );
}
//verify that there are either no remaining characters, or that
//all remaining characters are whitespace characters
while ( *p != 'n' )
{
//verify that remaining character is whitespace character
if ( !isspace( (unsigned char)*p ) )
{
printf( "Error converting number!n" );
exit( EXIT_FAILURE );
}
p++;
}
//print valid input
printf( "Input is valid.nYou entered: %ldn", l );
}

该程序具有以下输出:

有效输入:

Please enter an integer: 39
Input is valid.
You entered: 39

同一行有效输入后的垃圾:

Please enter an integer: 39 jdsuoew
Error converting number!

尝试输入浮点数而不是整数:

Please enter an integer: 1.0
Error converting number!

尝试输入太大的数字,以至于无法表示为long int

Please enter an integer: 10000000000000000000000000
Number out of range!

由于可能存在一堆错误的输入,因此您可能应该只查找正确的输入:'1''0'

"我也想接受0001...">

我只是从你的解释中假设你不想接受某事 喜欢:0011

我会从缓冲区的尽头看向起点。 换句话说: 我只会在缓冲区末尾查找单个'1',然后查找'0'(零) 直到你到达buf的开始.

其他一切都是错误的输入

由于您可以任意选择缓冲区大小,因此可以编写如下内容:

#define BUFF_SZ 15
...
char buf[BUFF_SZ];
...
while (buf[++i]); // <-- to avoid measuring buffer size at runtime.

下面是一个带有返回正确结果的函数的代码示例:

#include <stdio.h>
int check_input (char *buf);    
int main()
{
char buf[15]; // large enough
scanf("%14s", buf);
if (check_input(buf) == 0) {  printf("Wrong input!"); return(1); };
... input OK ...
return (0);
}
// function returns:    1: on success,  0: on wrong input
int check_input (char *buf)
{
int i=0;
while (buf[++i]);   // it will stop counting when NULL char is found ..
// so it's like 'strlen(buff)' 
// without unnecessary including <string.h>

// buffer is set at end so check if it ends with '1' ..                  
if (buf[--i] != '1')     return (0);

// now, check all buffer backwards to make sure that ALL of those are '0's..
while ((--i) > 0) 
if (buf[i] != '0')    return (0);
return (1);
}

我已经将最重要的部分写成功能,因此更具可读性。

我希望这能有所帮助。

相关内容

  • 没有找到相关文章

最新更新