Dataslope logoDataslope

Data Types

int, char, float, double, and friends — what they store, how big they are, and when to use each

C is a statically typed language. Every variable, every function parameter, and every return value has a type that is known at compile time. The type controls three things:

  • How many bytes are reserved.
  • How the bits are interpreted (signed integer? floating point? character?).
  • What operations are legal (you can add two ints; you can't add a function to a string).

The fundamental types

TypeTypical sizeWhat it stores
char1 byteA single small integer; usually used to store one ASCII character
short2 bytesA small integer
int4 bytesThe "default" integer; fast on most CPUs
long4 or 8 bytesA larger integer (size depends on the platform)
long long8 bytesAt least 64 bits of integer
float4 bytesSingle-precision floating point (~6–7 decimal digits)
double8 bytesDouble-precision floating point (~15–16 decimal digits)

Sizes are not nailed down by the C standard — only minimums are guaranteed. To find the exact size on your system, use sizeof:

Code Block
C 17 (201710L)

%zu is the printf format for size_t, the unsigned integer type that sizeof returns.

Signed and unsigned

Every integer type comes in two flavors:

  • Signed (the default): can hold negative and positive values. The most significant bit acts as a sign.
  • Unsigned: only non-negative values, but the range goes twice as high.
int      a = -100;       // signed, default
unsigned int b = 100;    // non-negative only

A 32-bit signed int ranges from roughly −2.1 × 10⁹ to +2.1 × 10⁹. A 32-bit unsigned int ranges from 0 to about 4.3 × 10⁹.

Characters: a sneaky kind of integer

char is the smallest integer type in C. It is one byte. A char can hold a number between roughly −128 and +127 (or 0–255 for unsigned char). When you write a character literal 'A', you are writing a small integer — the ASCII code for A, which is 65.

Code Block
C 17 (201710L)

%c says interpret this number as an ASCII character. %d says interpret this number as a decimal integer. The bits in the variable are identical either way — it is the format string that decides how to display them.

Floating-point numbers

For numbers with a fractional part, use float (less precision) or double (more precision). double is the default for fractional literals like 3.14, and is what most code should use unless memory is tight.

Code Block
C 17 (201710L)

%.5f says "print this double with 5 digits after the decimal point". %f without modifiers uses 6 digits by default.

Floating point is not exact

Decimal fractions like `0.1` cannot be represented exactly in binary floating point — just like `1/3` cannot be written exactly in base 10. The number you store is a very close approximation. This is why `0.1 + 0.2` is famously not exactly `0.3` in almost every programming language.

Code Block
C 17 (201710L)

For money, dates, or anything where exactness matters, do not use floating point. Use integers and track the units yourself (e.g. cents instead of dollars).

Integer division vs floating-point division

Beware: in C, dividing two integers produces an integer — fractional parts are thrown away.

Code Block
C 17 (201710L)

(double)a is a cast: it temporarily reinterprets a as a double for the purpose of the expression. The original a is unchanged.

%% inside a format string is how you print a single literal %.

Type conversions

C automatically converts between numeric types in many places (called implicit conversion). Mostly it does what you want, but a few patterns surprise beginners:

int    n = 10;
double d = n;          // ok: 10 -> 10.0
int    m = 3.7;        // ok but lossy: m becomes 3 (truncated, not rounded)

To make a conversion explicit (and to silence compiler warnings), use a cast (type)expression:

double price = 9.99;
int    dollars = (int)price;   // 9

A note on bool

C originally had no boolean type — programmers used int with 0 for false and any non-zero value for true. C99 added a real boolean type via the header <stdbool.h>:

Code Block
C 17 (201710L)

You may still see older code use int for boolean values. Both work.

A picture: types and the bits they reserve

Same memory, different sized boxes, different bit interpretations. The CPU has separate instructions for integer arithmetic and floating-point arithmetic — the type tells the compiler which to emit.

Challenge: average of three numbers

Challenge
C 17 (201710L)
Average three integers, printed as a decimal

Three variables a, b, and c are set to 10, 20, and 33. Compute their average as a real number (not truncated to an integer) and print exactly:

average = 21.00

Use %.2f to format the result with two digits after the decimal point.

QuestionSelect one

What will this program print?

#include <stdio.h>
int main(void) {
  int a = 7, b = 2;
  printf("%d\n", a / b);
  return 0;
}

3.5

4

3

A compile-time error.

QuestionSelect one

Which type would you choose to store the temperature of a refrigerator in degrees Celsius with one digit of precision (e.g. 4.0, -1.5)?

int — temperatures are whole numbers.

char — temperatures fit in one byte.

double — for accurate fractional values.

unsigned int — temperatures are always positive.

On this page