如何在C中使用read()系统调用从stdin中读取整数值?

c3frrgcw  于 2023-04-29  发布在  其他
关注(0)|答案(3)|浏览(212)

如何使用read()系统调用从stdin中读取整数值?

#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int main(){
    int n;
    read(0,&n,sizeof(n));
    printf("[%d]\n",n);
    return 0;
}

输出:

54
[668725]
yws3nbqq

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()来完成转换。例如:

scanf("%d", &n);
tquggr8v

tquggr8v2#

当从文件中阅读整数时,你必须非常非常清楚整数是如何存储在该文件中的。它是一个人类可读的文本或“ASCII”文件?还是机器可读的二进制文件?
在文本文件中,整数将由 characters 表示,与数字的 decimal(或十六进制或其他基数)表示的 digits 匹配。
但在二进制文件中,整数将由与内存中整数的二进制表示完全匹配的字节表示。
您要读取的是哪种文件?它看起来像是在尝试读取文本,但read()通常对于阅读二进制数据文件更有用。
让我们考虑一个例子。让我们想想9281这个数字。在文本文件中,此数字将由四个字符(四个字节)表示:9281。在ASCII中,字符9281具有十六进制值0x390x320x380x31,因此如果我们使用某种十六进制转储程序查看文件,这些就是我们看到的值。
另一方面,包含数字9281的二进制文件将包含值为0x240x41的两个字节。这些价值观从何而来?9281的基数是0x2441。(如果我们查看文件的文本,我们会看到字符A$,对应于十六进制值0x410x24,虽然这不是很有趣,具体字符A $在这里几乎是随机的/无意义的。)
根据整数是两个字节还是四个字节(16位还是32位),int可能会在文件中占用更多空间。此外,字节可能会以与预期不同的顺序出现。
最后,回答你的问题:如果它是一个 * 二进制 * 文件,你可以读它或多或少像你的问题中的代码。但如果它是一个 text 文件,那么使用fscanffgets读取一行文本,然后使用strtol或其他函数将字符串转换为整数会容易得多。使用read从文本文件中读取并转换整数,可能看起来像这样:

char buf[11];
int r;
r = read(0, buf, 10);
if(r > 0) {
    buf[r] = '\0';
    int n = atoi(buf);
    printf("[%d]\n",n);
}
bq3bfh9z

bq3bfh9z3#

函数read将从文件描述符中读取原始字符。
如果你想尝试将一个字符序列转换为int,你可以使用函数strtol。但是,使用该函数要求字符序列是有效的字符串,这意味着它必须以空字符终止。函数read不会在输入的末尾添加终止空字符。因此,您必须将其添加到适当的位置。
此外,在处理基于行的用户输入时,通常建议使用函数fgetsgetline。函数read不是一次阅读一行的,因为一旦遇到换行符,就无法告诉它停止。
简单的程序通常使用scanf,如下所示:

int n;
if ( scanf( "%d", &n ) == 1 )
{
    printf( "Input was successfully converted to %d.\n", n );
}
else
{
    printf( "Input conversion failed!\n" );
}

从标准输入读取并转换一个整数。然而,这具有若干缺点。例如:

  • scanf不会匹配整行。它将在行中至少保留换行符,即can cause trouble
  • 它将接受诸如6abc的输入作为数字6的有效输入。
  • 如果数字太大或太小而不能表示为int,则行为未定义,您无法检测到此行为。

由于这些原因,通常不建议使用scanf进行用户输入。通常最好将fgets/getlinestrtol结合使用。
下面是一个示例程序,它提示用户输入一个数字并尝试转换它。如果此转换失败,它会自动重新提示用户。该程序将执行广泛的输入验证。我不确定这是否是你正在寻找的。

#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.

相关问题