#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
//forward declaration
int get_int_from_user( const char *prompt );
int main( void )
{
int num;
num = get_int_from_user( "Please enter an integer: " );
printf( "Input successfully converted to %d.\n", num );
}
//This function will attempt to read one integer from the user. If
//the input is invalid, it will automatically reprompt the user,
//until the input is valid.
int get_int_from_user( const char *prompt )
{
//loop forever until user enters a valid number
for (;;)
{
char buffer[1024], *p;
long l;
//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;
l = strtol( buffer, &p, 10 );
if ( p == buffer )
{
printf( "Error converting string to number!\n" );
continue;
}
//make sure that number is representable as an "int"
if ( errno == ERANGE || l < INT_MIN || l > INT_MAX )
{
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 l;
continue_outer_loop:
continue;
}
}
此程序具有以下行为:
Please enter an integer: abc
Error converting string to number!
Please enter an integer: 10000000000000000
Number out of range error!
Please enter an integer: 60.5
Unexpected input encountered!
Please enter an integer: 6abc
Unexpected input encountered!
Please enter an integer: 25
Input successfully converted to 25.
3条答案
按热度按时间yws3nbqq1#
看起来你的输入是ASCII字符
'5'
和'4'
,后面跟着一个新的行字符'\n'
。将它们读入一个四字节缓冲区,用整数n
表示。显然,这个整数被初始化为零(在C中不确定),所以缓冲区的第四个字节(不是由read()
调用设置的)是零,而不是一个随机数。"54\n\0"
的十进制值为53、52、10、0。在您的机器架构中,整数以小端顺序存储(在C中也不保证),因此这四个字节变为53 + 25652 + 6553610 + 16777216*0 = 668725。如果你想从输入中读取一串ASCII十进制数字,并将其转换为相应的整数,你可以编写自己的代码来一次读取一个数字,检查这是一个数字,即。即在
'0'
到'9'
范围内,通过减去'0'
将其转换为值,然后将整数值(初始化为0)乘以每个数字的10,然后添加该数字。也可以在将字符读入缓冲区后使用
scanf()
或strtol()
来完成转换。例如:tquggr8v2#
当从文件中阅读整数时,你必须非常非常清楚整数是如何存储在该文件中的。它是一个人类可读的文本或“ASCII”文件?还是机器可读的二进制文件?
在文本文件中,整数将由 characters 表示,与数字的 decimal(或十六进制或其他基数)表示的 digits 匹配。
但在二进制文件中,整数将由与内存中整数的二进制表示完全匹配的字节表示。
您要读取的是哪种文件?它看起来像是在尝试读取文本,但
read()
通常对于阅读二进制数据文件更有用。让我们考虑一个例子。让我们想想9281这个数字。在文本文件中,此数字将由四个字符(四个字节)表示:
9
2
8
1
。在ASCII中,字符9
、2
、8
和1
具有十六进制值0x39
、0x32
、0x38
和0x31
,因此如果我们使用某种十六进制转储程序查看文件,这些就是我们看到的值。另一方面,包含数字9281的二进制文件将包含值为
0x24
和0x41
的两个字节。这些价值观从何而来?9281的基数是0x2441
。(如果我们查看文件的文本,我们会看到字符A
和$
,对应于十六进制值0x41
和0x24
,虽然这不是很有趣,具体字符A $
在这里几乎是随机的/无意义的。)根据整数是两个字节还是四个字节(16位还是32位),
int
可能会在文件中占用更多空间。此外,字节可能会以与预期不同的顺序出现。最后,回答你的问题:如果它是一个 * 二进制 * 文件,你可以读它或多或少像你的问题中的代码。但如果它是一个 text 文件,那么使用
fscanf
或fgets
读取一行文本,然后使用strtol
或其他函数将字符串转换为整数会容易得多。使用read
从文本文件中读取并转换整数,可能看起来像这样:bq3bfh9z3#
函数
read
将从文件描述符中读取原始字符。如果你想尝试将一个字符序列转换为
int
,你可以使用函数strtol
。但是,使用该函数要求字符序列是有效的字符串,这意味着它必须以空字符终止。函数read
不会在输入的末尾添加终止空字符。因此,您必须将其添加到适当的位置。此外,在处理基于行的用户输入时,通常建议使用函数
fgets
或getline
。函数read
不是一次阅读一行的,因为一旦遇到换行符,就无法告诉它停止。简单的程序通常使用
scanf
,如下所示:从标准输入读取并转换一个整数。然而,这具有若干缺点。例如:
scanf
不会匹配整行。它将在行中至少保留换行符,即can cause trouble。6abc
的输入作为数字6
的有效输入。int
,则行为未定义,您无法检测到此行为。由于这些原因,通常不建议使用
scanf
进行用户输入。通常最好将fgets
/getline
与strtol
结合使用。下面是一个示例程序,它提示用户输入一个数字并尝试转换它。如果此转换失败,它会自动重新提示用户。该程序将执行广泛的输入验证。我不确定这是否是你正在寻找的。
此程序具有以下行为: