When programming in C++, there are many situations when you need to read data from a stream or from standard input.
Reading and storing data while classifying it into different formats is a key part of how programs run. Without a means to call upon external data as input, programs would be unable to operate with any data beyond what users input with cin or similar input functions.
The C++ functions scanf and fscanf read data and store data.
- Scanf (pronounced: scan-eff) reads formatted data from the standard input and places it into a specified location.
- Fscanf (pronounced: eff-scan-eff) reads formatted data from a pointer indicating a file object that determines the input stream to read data from.
How the fscanf and scanf Functions Work
Both of these functions work by reading data and then storing the data according to the parameter format as pointed in their additional arguments. Those arguments point to allocated objects of the type specified within the corresponding format-string.
For both functions, the format string establishes the interpretation of the argument. The format-string can only contain multibyte characters that begin and end with the initial conversion state. In order to use scanf and fscanf in C++, you have to identify the string that format-string actually points to.
These strings can contain any of the following types of characters:
- White Space Characters. White space characters are specified by isspace(). They include blanks and newline characters. When scanf or fscanf read a white space character, they do not store it. This means that one white space character is essentially the same as any number of white space characters in the format-string – quantity produces no functional difference.
- Non-White Space Characters. This includes all characters that are not blanks or newlines, with the exception of the percentage sign (%) character. Upon reading a non-white space character, scanf and fscanf will read, but not store, the matching non-white space character specified in the format-string until the next character in the input stream does not match. That is when the function ends.
- Format Specifiers. Conversion specifications beginning with the percentage sign character specify the type and format of any data that scanf or fscanf needs to retrieve. Upon reading this character, both functions will read and convert the following characters into the values of the format specified. This value must be assigned to an argument in the argument list.
All three of these functions read the format-string from left to right. Every character without a percentage sign preceding should match the sequence of characters called in the input stream.
If the characters do not match, the function terminates with a matching failure. The conflicting character remains in the input stream as if the program never read it.
Once the program reads its first format specifier, it converts the value of the first input field according to that specification in the argument list. The second format specifier tells the program to convert the second input field and store it in the second argument, and so on. This orderly pattern continues until the format-string ends.
Working with the Format Specifier
The format specifier for fscanf and scanf has the following form:
The specifier character at the end of this statement is the most important element of the format specifier. It defines which characters scanf or fscanf will extract, lays out how it will interpret those characters, and identifies their corresponding argument type.
C++ programmers need to be familiar with 12 types of format specifiers:
- Integers. Specify integers using “i”. This format extracts an unlimited number of positive or negative digits. This is a signed argument, and although it assumes decimal digits, an “o” prefix changes it octal digits and a “0x” prefix introduces hexadecimal digits.
- Decimal Integers. Specify decimal integers using “d” for a signed argument or “u” for an unsigned argument. This format extracts any number of decimal digits. You can use both positive and negative integers.
- Octal Integers. Specify octal integers as an unsigned argument using “o”. These digits use a base-eight numbering system. This format supports positive and negative numbers.
- Hexadecimal Integers. Specify hexadecimal digits with an unsigned argument using “x”. This format supports positive and negative numbers.
- Floating Point Numbers. Specify a floating number format using “f”, “e”, “g”, or “a”. Floating point numbers can contain decimal points and be either positive or negative. C99-compliant implementations also support hexadecimal floating-point format using the “0x” prefix.
- Characters. Specify the next character using “c”. If the format specifier features a width other than 1, the function will read that exact number of characters and store them in successive array locations as per the argument. It will not append null characters at the end.
- Character Strings. Specify strings of characters using “s”. This format lets you specify any number of non-whitespace characters. It will stop at the first whitespace character found and automatically add a null character at the end of the sequence.
- Pointer Addresses. Specify pointer addresses with “p”. This format extracts a sequence of characters that represent a pointer. The particular format of the pointer depends on the system and library you are using.
- Scansets. Specify a specific scanset by including the characters you wish to scan for inside a pair of brackets.
- Negated Scansets. Specify a negated scanset using brackets with a “^” prefix inside the brackets. This will read any characters not defined in the brackets.
- Count. To store the number of characters read so far from the standard input at the pointed location without consuming input, specify “n”.
- Identity. Specifying “%” is an identity. One “%” followed by a second “%” is the same as a single “%”.
There are additional sub-specifiers available in the format specifier argument. These can change the function of fscanf and scanf according to commonly needed behaviors.
- The asterisk [*] is optional. It tells the program to read the data from the stream but to avoid storing it in the location that the argument points to.
- The [width] sub-specifier tells the reading operation to read a specific number of characters.
- The [length] sub-specifier tells the program which type of storage to expect according to a series of formats defined by C99.
Unlocking fscanf and scanf for Multithreading
Both fscanf and scanf can work safely in multithreaded applications. fscanf_unlocked and scanf_unlocked are the multithread variants of both these functions.
The unlocked versions of these functions are not thread-safe, so you must call it only when the invoking thread owns the FILE object – for instance, after successfully calling flockfile() or ftrylockfile().
Example Using scanf to Return Data
In order to use scanf, you must include the <stdio.h> standard header in your code. Combined with printf, it allows you to enter and return data quickly. Here is an example:
int main ()
char str ;
printf ("Enter your family name: ");
printf ("Enter your age: ");
printf ("Mr. %s , %d years old.\n",str,i);
printf ("Enter a hexadecimal number: ");
printf ("You have entered %#x (%d).\n",i,i);
This example uses scanf alongside standard input to ask the user to input various types of information. It specifies the type of data it asks for, which allows for deeper implementations within the context of the program. Example responses could include:
Enter your family name: Jackson
Enter your age: 30
Mr. Jackson, 30 years old.
Enter a hexadecimal number: ff
You have entered 0xff (255).
Example Using fscanf To Return Data
Functionally, fscanf works in a similar way to scanf. The main difference is that fscanf has to read from a file, which means you have to identify a file to read from and then tell the program what to look for inside the file. For example:
int main ()
char str ;
FILE * pFile;
pFile = fopen ("myfile.txt","w+");
fprintf (pFile, "%f %s", 3.1416, "PI");
fscanf (pFile, "%f", &f);
fscanf (pFile, "%s", str);
printf ("I have read: %f and %s \n",f,str);
This example creates “myfile.txt” and writes a float number and a string into the file. The stream then rewinds, and the program reads both of those values with fscanf. The output it produces will look like this:
I have read: 2.718 and e
Are scanf and fscanf Useful For Professional C++ Programmers?
Both scanf and fscanf are important steps for any C++ student to pass on the way to becoming a professional programmer. In more advanced scenarios, you can use these functionals to input vector data types and other complex forms of information into a C++ program.
However, it can act unpredictably when dealing with human errors. If a user doesn’t input the exact type of information in the exact format the program expects, it may not successfully read any of the data. This makes it an uncommon sight in environments where users generally expect programs to run predictably even if they make mistakes inputting data.
In C++, both scanf and fscanf generally operate much faster than their iostream equivalents. Commercial applications designed to maximize speed while processing predictable inputs may use them to great effect to achieve that goal.