fscanf in C/C++: reading from a file

Hey there! In this article, we’ll be diving into the fscanf function. This function is pretty similar to scanf, but instead of reading values from standard input, it reads them from a file. We’ll kick things off with an overview using examples and then delve into the format specifiers this function supports (which are the same as scanf, so if you’re familiar with it, you will find them familiar). At the end, there are some exercises for further practice.

Illustration of fscanf

How to read values from a file using fscanf

To read values from a file, you can make use of the fscanf function. This function is declared in the header file <stdio.h>. In C++, you can include <cstdio>. The function looks like this:

int fscanf ( FILE * stream, const char * format, ... );
  • The first argument should be a pointer to the file from which you want to read.
  • The second argument is the format string which dictates how the file should be read.
  • Then, you pass as many arguments as fscanf expects based on the format string.
  • The function returns the number of values it read from the file. If everything goes well, this number should be equal to the number of arguments following the format string.

Let’s look at a few examples:

#include <stdio.h>

int main() {
  FILE * f = fopen("input.txt", "r");
  int x;
  int n = fscanf(f, "x: %d", &x);
  fclose(f);

  printf("x = %d, n = %d", x, n);

  return 0;
}

input.txt:

x: 4

Program output:

x = 4, n = 1

In the program above, we read an int variable from a file using the format specifier %d (more on specifiers shortly). After reading, we printed out x and the number of arguments read.

Now, let’s try reading something a bit more complex:

#include <stdio.h>

int main() {
  FILE* f = fopen("input.txt", "r");
  unsigned int x;
  char s[100];
  float pi;
  int n = fscanf(f, "hex: %x, s = %s\nfloat <- %f", &x, s, &pi);
  fclose(f);

  printf("x = %d, s = %s, pi = %f, n = %d", x, s, pi, n);

  return 0;
}

input.txt:

hex: 0xABC, s = fscanf
float <- 3.14

Program output:

x = 2748, s = fscanf, pi = 3.140000, n = 3

As you can see, fscanf managed the complex format just fine. Let’s now “mess up” the input.txt file so that fscanf can only read the first two values:

hex: 0xABC, s = fscanf
UNKNOWN <- 3.14

With the start of the second line altered, let’s run the program again and see the output:

x = 2748, s = fscanf, pi = 0.000000, n = 2

Everything here is as expected:

  • fscanf could read the first two values since they remained unchanged.
  • However, when reading the second line of the file, fscanf hits the unexpected ‘U’ character and stops reading.
  • Ultimately, we see that only two values were read (n equals two). pi remains with its default value (in this case, zero).

What will be displayed on the screen?

#include <stdio.h>

int main() {
  FILE* f = fopen("data.txt", "r");
  char word[50];
  double number;
  int n = fscanf(f, "%s = %lf", word, &number);
  fclose(f);

  printf("word = %s, number = %lf, n = %d", word, number, n);

  return 0;
}

data.txt:

result = 42.58
word = result, number = 42.580000, n = 2
word = 42.58, number = 0.000000, n = 1
word = result, number = 42.580000, n = 1
word = result, number = 0.000000, n = 2

Now, let’s have a look at all the possible format specifiers you can use with the fscanf function.

Format specifiers

The structure of the specifier in fscanf differs slightly from the one in fprintf. Here’s a look (optional modifiers are in square brackets):

%[*][width][length]type

From this, only the percentage sign and type are mandatory; you can skip the rest. These specifiers are pretty much the same as the ones in scanf (yeah, the one that reads from standard input, not a file).

Types

TypeDescriptionExampleFile
i

Reads an integer in octal, decimal, or hexadecimal.

fscanf(f, "%i", &x); // x = 987
fscanf(f, "%i", &x); // x = -987
fscanf(f, "%i", &x); // x = 987

01733
-987
0x3db

d

Reads a decimal integer.

fscanf(f, "%d", &x); // x = -987

-987

u

Reads a positive decimal integer.

fscanf(f, "%u", &x); // x = 987

987

o

Reads an octal integer.

fscanf(f, "%o", &x); // x = -987

-1733

x

Reads a hexadecimal integer.

fscanf(f, "%x", &x); // x = -987
fscanf(f, "%x", &x); // x = 987

-3db
0x3db

f, e, g, a

Reads a floating-point number.

fscanf(f, "%f", &x); // x = 12.34
fscanf(f, "%f", &x); // x = 12.34
fscanf(f, "%f", &x); // x = 12.34
fscanf(f, "%f", &x); // x = 12.34

1.234e+01
12.34
987
0x1.8ap+3

c

Reads a character.

fscanf(f, "%c", &x); // x = 'C'

C

s

Reads a string until the first whitespace.

fscanf(f, "%s", &x); // x = "C++"

C++

p

Reads a memory address.

fscanf(f, "%p", &x); // x = 0x16dc

0x16dc

[characters]

Reads a string until it finds a character that isn’t among those inside the brackets.

fscanf(f, "%[1a]", &x); // x = "aa1"

aa1398

[^characters]

Reads a string until it encounters a character that matches one from inside the brackets, after the ^.

fscanf(f, "%[^a1]", &x); // x = "C++"

C++11

n

Doesn’t read anything. Writes the number of characters read up to this point.

fscanf(f, "C++%n11", &x); // x = 3

C++11

%%

Reads the percentage sign.

fscanf(f, "%%%c", &x); // x = 'd'

%d

Ignoring input

You can add an asterisk right after the percentage sign if you’re like, “I don’t wanna save this value”:

FILE * f = fopen("input.txt", "r");
int x;
fscanf(f, "Skip: %*d, save: %d", &x);
printf("Number: %d", x);

input.txt:

Skip: 123, save: 456

Output:

Number: 456

You can slap that asterisk on any type from the table above, not just numbers.

Width

We can define the maximum number of characters to be read by the fscanf function:

FILE * f = fopen("input.txt", "r");
char s[4]; // 3 characters + '\0'
fscanf(f, "%3s", s);
printf("Read: %s", s);

input.txt:

C++11

Output:

Read: C++

Just like the asterisk, you can specify a width for any type.

Length

By default, fscanf reads values of type int, unsigned int, float, and char (depending on the specifier type). To read, say, a value into a long long int variable, we need to explicitly state the length:

#include <math.h>
#include <stdio.h>

int main() {
  FILE * f = fopen("input.txt", "r");
  long long int x;
  printf("Number: ");
  fscanf(f, "%lld", &x);
  //      ^ added ll for long long int
  printf("Read: %lld\n", x);
  //               ^ don't forget this in printf either

  return 0;
}

input.txt:

Number: 10000000000

Output:

Read: 10000000000

Without specifying the size, the output might look something like this:

Read: 5705032704

This odd output is because ten billion just doesn’t fit into the int type, which fscanf tries to read without a specified size.

Here’s a quick size chart for you:

SizeType
hh

signed char / unsigned char

h

short int / unsigned short int

l

long int / unsigned long int

ll

long long int / unsigned long long int

j

intmax_t / uintmax_t

z

size_t

t

ptrdiff_t

L

long double

Exercises

  1. Reading various data types:
    Write a C++ program that uses fscanf to read different data types from a file. The file should have an integer, a float, and a string. After reading, the program should display these values.
  2. Handling read errors:
    Modify your data file so one of the lines doesn’t match the format you’re expecting. Then tweak your program to handle this gracefully, like maybe by printing an error message.
  3. Using different format specifiers:
    Write a program showcasing the use of different format specifiers with fscanf. Set up a file with various data (like integers, floats, strings, hex numbers) and pull them from the file, displaying the results.

Discussion

© 2023, codelessons.dev