How can I read integer value from stdin using read() system call?
#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;
}
OUTPUT:
54
[668725]
How can I read integer value from stdin using read() system call?
#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;
}
OUTPUT:
54
[668725]
It looks like your input was the ASCII characters '5'
and '4'
followed by a new line character '\n'
. You read them into a four-byte buffer, represented by your integer n
. Apparently that integer was initialized to zero (not assured in C), so the fourth byte of the buffer, not set by the read()
call, was zero and not a random number.
The decimal values of "54\n\0"
are 53, 52, 10, 0. On your machine architecture, integers are stored in little-endian order (also not assured in C), so those four bytes become 53 + 256*52 + 65536*10 + 16777216*0 = 668725.
If you want to read a string of ASCII decimal digits from your input and convert that to the corresponding integer, you could write your own code to read a digit at a time, check that is a digit, i.e. in the range '0'
to '9'
, convert it to its value by subtracting '0'
, and then multiplying your integer value (initialized to 0) by 10 for each digit and then adding that digit.
Or you can use scanf()
, or strtol()
after reading the characters into a buffer, to do that conversion for you. E.g.:
scanf("%d", &n);
The function read
will read raw characters from the file descriptor.
If you want to attempt to convert a sequence of characters to an int
, you can use the function strtol
. However, using that function requires that the sequence of characters is a valid string, which means that it must be terminated by a null character. The function read
will not add a terminating null character at the end of the input for you. Therefore, you will have to add it yourself in the appropriate place.
Also, when dealing with line-based user input, it is usually recommended to use the function fgets
or getline
. The function read
is not designed for reading one line at a time, because there is not way to tell it to stop once it encounters the newline character.
Simple programs often use scanf
, like this:
int n;
if ( scanf( "%d", &n ) == 1 )
{
printf( "Input was successfully converted to %d.\n", n );
}
else
{
printf( "Input conversion failed!\n" );
}
to read and convert one integer from standard input. However, this has several disadvantages. For example:
scanf
will not match the entire line. It will leave at least the newline character on the line, which can cause trouble.6abc
as valid input for the number 6
.int
, the behavior is undefined and you cannot detect this.For these reasons, is it is generally not recommended to use scanf
for user input. It is usually better to use fgets
/getline
in combination with strtol
.
Here is an example program which prompts the user to enter a number and attempt to convert it. If this conversion fails, it automatically reprompts the user. This program will perform extensive input validation. I am not sure if this is what you are looking for.
#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;
}
}
This program has the following behavior:
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.
When reading integers from a file, you have to be very, very clear on how the integers are stored in that file. Is it a human-readable, text or "ASCII" file? Or is it a machine-readable, binary file?
In a text file, an integer will be represented by characters matching the digits of the decimal (or perhaps hexadecimal or some other base) representation of the number.
But in a binary file, an integer will be represented by bytes which exactly match the integer's binary representation in memory.
Which kind of file are you trying to read? It looks like you're trying to read text, but read()
is usually more useful for reading binary data files.
Let's consider an example. Let's think about the number 9281. In a text file, this number would be represented by four characters (four bytes): 9
2
8
1
. In ASCII, the characters 9
, 2
, 8
, and 1
have hexadecimal values 0x39
, 0x32
, 0x38
and 0x31
, so if we looked at the file using some kind of a hex dump program, those are the values we'd see.
On the other hand, a binary file containing the number 9281 would contain two bytes with the values 0x24
and 0x41
. Where do those values come from? Well, 9281 in base 16 is 0x2441
. (If we looked at the file's text, we'd see the characters A
and $
, corresponding to the hex values 0x41
and 0x24
, although that's not very interesting, and the specific characters A $
are almost random/meaningless in this context.)
Depending on whether integers are two bytes or four bytes (16 bits or 32 bits), an int
might take up more space in your file. Also the bytes might appear in the other order than you expected.
Finally, in answer to your question: If it's a binary file, you can read it more or less like the code in your question. But it it's a text file, it will be much easier to read it using fscanf
, or fgets
to read a line of text, followed by strtol
or some other function to convert a string to an integer. To read and convert an integer from a text file, using read
, might look something like this:
char buf[11];
int r;
r = read(0, buf, 10);
if(r > 0) {
buf[r] = '\0';
int n = atoi(buf);
printf("[%d]\n",n);
}