Using printf() and scanf()

The functions printf() and scanf() are trickier and more powerful than people usually think.

Tips here apply to related functions, e.g., fprintf(), vprintf() and sscanf().

Online help

In case you need a quick reference, a complete online specification (for C99) can be found in fprintf() and fscanf().

Under Linux, try to type
man 3 printf or man fprintf
or
man scanf

Left alignment: “-” (as in "%-6d")

Default is to align to the right.

No %lf in printf(), no %g in scanf()

In printf(), always use %f for both double and float, because float will be automatically upgraded to double. Most compilers, however, accepts %lf.

On the other hand, in scanf(), use %f for float, %lf for double.

Do not scan a string by "&s"

It applies to both printf() and scanf()

Suppose char s[32] = "abc"; then
Right: scanf("%10s", s); or printf("%s", s);
Wrong: scanf("%10s", &s); or printf("%s", &s);

Print the first five characters: printf("%.5s", s)

This is a nice trick printf("%.5s", s) to print only the first five characters, note printf("%5s", s); won't work. Even better, you can use "%.*s" to specify a variable width like
printf("%.*s", n, s);

The trick can be used as "safe" string copying:

char *strncpy_safe(char *t, const char *s, int n)
{
  sprintf(t, "%.*s", n-1, s);
  return t;
}

See an example.

Scan characters or strings: %5c vs. %5s in scanf()

Both can be used to read strings, but the differences are:

  1. %5s skips spaces, %5c counts spaces.
  2. %5s adds a '\0' in the end, %5c doesn't.

So %5c is kind of like memcpy().

See an example.

Spaces in scanf()

A space in the format string fmt of scanf(fmt, ...) means to skip spaces,

Leading spaces before % is usually skip, but not in the case of %c, or an ordinary character
sscanf("  abc", "%c", &c); makes c == ' ',
sscanf("abc", "%c", &c); makes c == 'a'.

An ordinary character (not space or %) in the format string is to be matched, however, you usually want to skip some leading spaces, so sscanf("\t\v x \n  =5", " x =%d", &x);
will work, while
sscanf("\t\v x \n  =7", "x=%d", &x);
won't.

See an example.

Use scanset “[]” in scanf()

The pattern %10[a-zA-Z+-] matches a string of maximal of 10 characters long, with every character in the set {a, b, c, ..., z, A, B, C, ..., Z, +, -}. (leading spaces are not skipped, to skip spaces use % 10[a-zA-Z+-]).
Use %10[]a-zA-Z+-] to include ']'; use %10[][a-zA-Z+-] to include ']' and '['.

%10[^a-zA-Z] matches a string of maximal of 10 characters long, with no character in the set {a, b, c, ..., z, A, B, C, ..., Z}. (leading spaces are not skipped, to skip spaces use % 10[a-zA-Z]).
Use %10[^]a-zA-Z] to exclude ']'; use %10[^][a-zA-Z] to exclude ']' and '['.

See an example.

How many characters have I scanned? %n

The format string %n can be used to indicate how many characters read so far. This is especially useful for sscanf(). Note %n does not count as one scanned item in the return value of sscanf().

It can be used to read an array of data from string in sscanf().

for (p = s, i = 0; i < 3; i++, p += next)
  if (1 != sscanf(p, "%lf%n", &x[i], &next))
    exit(1);

see the example.

Print hexadecimal numbers: %#x == 0x%x

In printf()"#" in %#x means the alternate form. For a hexadecimal number, it usually adds “0x” before the number, so it's pretty much the same as 0x%x.

Print and scan 64-bit integers

Old Visual C++ and Borland C++ use "%I64d" to print 64-bit integers. On 64-bit Unix/Linux compilers, "%lld" is often used instead, for long long is usually 64-bit.

In C99, we have PRId64 and SCNd64 defined in <inttypes.h>. They are equivalent to "I64d" or "lld". There are also similar macros like PRIx64, PRIu64, etc. Note that “%” is not included, for we may need alignment and width flags after “%”. See the example.

#include <stdio.h>
#include <inttypes.h>

/* constant 64-bit integer */
#if defined(_MSC_VER) || defined(__BORLANDC__)
  #define CI64(x) (x ## i64)
#else
  #define CI64(x) (x ## ll)
#endif

int64_t x = CI64(3141592653589793);
printf("The number is %-20" PRId64 "\n", x);

In scanf(), use %f to read float, and %lf to read a double.

If you just need a large integer, try also %jd (formally, it's for intmax_t). This only works for C99.

%z for size_t

Some compiler gives a warning if you try to print a size_t with %d. So use %z instead for C99,
printf("%z\n", sizeof(int));

This trick does not work for C89. A workaround is
printf("%u\n", (unsigned) sizeof(int));
On a 64-bit machine, it is easier to print a double
printf("%lf\n", 1. * sizeof(int));