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
| Type | Typical size | What it stores |
|---|---|---|
char | 1 byte | A single small integer; usually used to store one ASCII character |
short | 2 bytes | A small integer |
int | 4 bytes | The "default" integer; fast on most CPUs |
long | 4 or 8 bytes | A larger integer (size depends on the platform) |
long long | 8 bytes | At least 64 bits of integer |
float | 4 bytes | Single-precision floating point (~6–7 decimal digits) |
double | 8 bytes | Double-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:
%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 onlyA 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.
%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.
%.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.
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.
(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; // 9A 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>:
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
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.
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.
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.