Recognizing Integers and Floats
In this tutorial, we will learn how scanf() function recognises integers and floats, especially when the user provides input in an unexpected format. So, let’s dive in.
In this tutorial, we will learn how scanf() function recognises integers and floats, especially when the user provides input in an unexpected format. So, let’s dive in.
When it comes to integers and floats, the scanf()
function, by default, skips whitespace characters (i.e., spaces, tabs, and newlines) because it does not consider them valid input. The following scanf()
function is no exception (here, a
and c
are integer variables and b
and d
are float variables):
scanf("%d%f%d%f", &a, &b, &c, &d);
Let’s assume the user provides the following inputs:
-1 12.55
-25
3.14159
Even though the inputs contain various whitespace characters, they will all be ignored by the scanf()
function, and the variables will receive the inputs as expected:
a = -1, b = 12.55, c = -25, d = 3.14159
Now, what if the user provides input like this?
-112.55-253.14159
I know that’s a weird scenario—maybe only a mischievous (or slightly psychopathic) user would do this—but let’s admit it: we cannot stop users from entering data this way.
Execute the following program with the above input and see the output for yourself:
#include <stdio.h>
int main() {
int a, c;
float b, d;
printf("Enter the values: ");
scanf("%d%f%d%f", &a, &b, &c, &d);
printf("The values are: %d %f %d %f", a, b, c, d);
return 0;
}
Output:
Enter the values: -112.55-253.14159
The values are: -112 0.550000 -253 0.141590
Hmmm! That’s weird. Why did we get this output? To explain this, we first need to see how the scanf()
function recognises integers and floats. For that, it is important to understand the concept of buffer storage.
The buffer storage, also known as the standard input buffer, is a temporary memory space that can hold user input, allowing the scanf()
function to read them completely. It is better if the scanf()
function waits for all the input, as this saves a lot of time, which is why buffer storage is useful. Wait! What? If scanf()
waits for the input, does it actually save time? Shouldn’t it be the opposite? Wouldn’t it be better if scanf()
read the input on the go? To answer these questions, we need to understand how scanf()
works behind the scenes.
There are several steps involved when it comes to reading inputs. Let’s take a closer look at these steps:
The program calls the scanf()
function. As soon as it is called, it communicates with the operating system by sending it a signal to read the data.
When we call the scanf() function, it does not read input directly from the keyboard. It communicates with the OS, which is responsible for providing inputs received from the user.
When you press a key on the keyboard, the scanf()
function does not read it magically. The keyboard hardware receives the signal from the pushed key and sends it to the operating system. This sends low-level information about the key pressed to the OS.
The OS receives the low-level information about the key from the keyboard hardware such as
But the OS doesn’t put all this information in the buffer. Instead, it converts the received information into an actual character. This character is stored in the buffer. For example, if ‘a’ is pressed, then the OS figures out the character and stores it in the buffer.
Your inputs are stored in what is called the standard input buffer. This buffer follows the FIFO order, i.e., data entered first is read first. If you like, you can edit this stored data (maybe remove some inputs using backspace on the screen, and the data will be modified in the buffer too). But, as soon as you press the enter key, the data stored in the buffer is removed and then provided to the scanf()
function by the OS.
As mentioned already, as soon as the enter key is pressed by the user, OS sends the signal to the scanf()
function that the data is available to read. The scanf()
function then reads the data from the buffer.
The scanf()
function stores the data in a variable, and in this way the input is read.
And that’s it! In this way, the data is retrieved by the scanf()
function.
In general, the activities at the system level are faster than the input and output procedures. For this reason, the scanf() function should not read the input directly from the keyboard because there are many negative consequences associated with it. First, scanf() has to wait for each user input, and during this time the program remains halted, slowing down execution. Second, the user can’t change the input once scanf() reads it. For this reason, the scanf() function does not read input on the go; instead, OS uses the buffer storage, which is used to store the data entered by the user so that when the entire input is fetched, it can be read all at once by the scanf() function, and if there is any modification, then it can be done too.
Coming back to the example, the input -112.55-253.14159
is stored in the buffer as follows:
Now, how the scanf()
functions reads the inputs, and provides them to their respective variables? Let’s learn this properly.
In our example program, the scanf()
looks like the following:
scanf("%d%f%d%f", &a, &b, &c, &d);
%d
is the first format specifier and it corresponds to the variable a
. In the buffer, we have the following content:
The scanf()
function considers integer values as valid characters. It also considers plus (+) and minus (-) signs at the beginning of the number. The scanf()
function sees the minus sign (-) as the first character in the buffer storage and reads it correctly because it thinks it is a valid character. It would also be able to read characters 1, 1, and 2, but as soon as it encounters the decimal point, it stops reading because the decimal point is not a valid character for an integer. Therefore, variable a
receives the value -112
, and the current state of the buffer looks like the following:
Notice how all the data is shifted to the left for reading purposes.
When scanf()
is instructed to read a floating-point number based on the format specifier, it follows a specific rule. It looks for an optional plus sign, an optional minus sign, and a sequence of digits (which may include a decimal point). It may also look for an optional letter ‘e’ or ‘E’, followed by an optional sign and one or more digits.
Let’s consider the example scanf()
call:
scanf(“%d%f%d%d”, &p, &q, &r, &s);
After reading the first input, scanf()
moves on to the %f
specifier, which indicates that it should read a floating-point number. Let’s assume the current state of the buffer is as follows:
Now, the scanf()
function will encounter the decimal point ‘.’ after the minus sign. It recognizes that the decimal point is valid for a floating-point number. Next, it picks the next two digits, ‘3’ and ‘3’. However, when it encounters the next character, ‘-‘, it realizes that it is not a valid character for a floating-point number. In this case, scanf()
puts the ‘-‘ character back into the buffer and considers the accepted floating-point number for the variable q as 0.33.
So, the final result is: q = 0.33 and the current state of buffer looks like the following:
The scanf() function has not finished reading the entire input. Let’s take a look at the current state of the buffer
and the scanf() function:
scanf(“%d%f%d%d”, &p, &q, &r, &s);
Your task is to determine the values stored in the variables r and s after the scanf() function reads the complete buffer. As a bonus, can you guess what happens to the newline character \n
at the end of the buffer?
Solution:
In the given format specifier "%d%f%d%d"
, the next specifier is %d
. So, scanf starts picking characters from the buffer. It first picks the minus sign ‘-‘, which is a valid character for an integer. Next, it picks the digits 2 and 5. However, when it encounters another minus sign ‘-‘, it recognizes that it is not a valid character for an integer after the digits 2 and 5. Therefore, scanf puts the minus sign back into the buffer. As a result, the value stored in variable r is -25. The current state of the buffer is as shown:
Moving on, the final specifier is %d
. scanf reads the remaining characters in the buffer, which are -98. It recognizes that the newline character \n
is not a valid character for an integer, so it puts it back into the buffer. Hence, the value stored in variable s is -98. The current state of the buffer is shown below:
Since we don’t have any more specifiers to process, the newline character \n
remains in the buffer. It will be processed by the next scanf call (if any).
So, the final values are: p = -110, q = 0.33, r = -25, and s = -98.
Just a quick note:
You might be wondering why we’re only focusing on integers and floats when there are other types like characters and strings to consider. The reason is that we want to explain how scanf() works in a thorough manner, and it’s simpler to start with integers and floats for now. As we continue with this course, we’ll also cover the other types and how they behave differently with the printf() and scanf() functions.
Leave a comment