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.


Handling Whitespaces

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.


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:

Step 1: The scanf() is called

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.

Step 2: You press a key on the keyboard

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.

Step 3: OS puts your input in the buffer

The OS receives the low-level information about the key from the keyboard hardware such as

  1. The key code (to identify the pressed key).
  2. Whether the key is pressed down or released.
  3. Modifier keys (Shift, Alt, Ctrl, etc.).

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.

Step 4: scanf() Reads Data from the buffer

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.

Step 5: Your program gets the value

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:

Buffer Storage

Now, how the scanf() functions reads the inputs, and provides them to their respective variables? Let’s learn this properly.


Reading Integers

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:

Buffer Storage

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:

Buffer Storage

Notice how all the data is shifted to the left for reading purposes.


Reading Floating-Point Values

After reading the integer value -112, the scanf() function has to read the floating-point value because the next format specifier is %f. This format specifier corresponds to the variable b, and therefore the next data goes in it.

The scanf() function looks for an optional sign (plus or minus) followed by a handful of numbers that may or may not have a decimal point in them in order to read a floating-point value (and the number may even begin with a decimal point, which is valid), and then an optional character ‘e’ or ‘E’ (if the number is provided in the scientific notation) followed by an optional sign and some digits.

In our example, we are left with the following characters in the buffer:

Buffer Storage

The remaining input is .55-253.14159
So, the next character to read is the decimal point (.). The scanf() considers it a valid character for the floating-point number, and hence it will read it. It will also read digits 5 and 5. After these digits, it encounters the minus (-) sign which is not a valid character in between (it will be valid if the character following it is either ‘e’ or ‘E’).

So, what’s inside variable b? You guessed it: 0.55.
At this point, we can say:

a = -112, b = 0.55

and the current status of buffer is

Buffer Storage

Reading the Remaining Inputs

Now as we know how to read integers and characters, it is easier to read the remaining input. We are left with these digits that we need to read: -253.14159

The next format specifier is %d which allows the scanf() to put value -253 straight inside the variable c. So, c = -253.

Buffer looks like the following:

Buffer Storage

The last format specifier is %f. The scanf() will read the remaining input from the buffer, which is .14159, and put it inside variable d. So, d = 0.14159.

Finally, our variables got values from the scanf() as follows:

a = -112, b = 0.55, c = -253, d = 0.14159

That’s the exact output we got from the program, but this time you know the proper reason why 😉

The buffer is now empty, which shows that the scanf() function has completed reading the input.

Buffer Storage

You might be wondering why we have only discussed how scanf() reads integers and floats when we also have other types like characters and strings. The reason is that we want you to understand how scanf() handles unusual and unexpected user input, and integers and floats are the simplest types to deal with. As you now have complete knowledge about the same, in the subsequent tutorials of this course, we will understand how functions like printf() and scanf() work with other data types.



Leave a comment

Leave a comment

Your email address will not be published. Required fields are marked *

Thank you for choosing to leave a comment. Please be aware that all comments are moderated in accordance with our policy. For more information, please review our comments policy. Rest assured that your email address will not be shared with anyone. Kindly refrain from using keywords in your comment. Let’s maintain a respectful atmosphere and engage in meaningful conversations.