In C, every variable has a fixed type, chosen when you declare it, and the type decides how much memory it uses and what it can hold.
Declaring variables#
int age = 21;
double price = 99.5;
char grade = 'A';
The type comes first, then the name, then optionally a starting value. A variable declared without a value holds whatever was in that memory before, so always initialise:
int total; // unknown value: a bug waiting to happen
int count = 0; // known
The common types#
| Type | Typical size | Holds |
|---|---|---|
char | 1 byte | one character, or a small number |
int | 4 bytes | whole numbers to about ±2.1 billion |
long long | 8 bytes | whole numbers to about ±9.2 × 10^18 |
double | 8 bytes | numbers with a fraction, about 15 significant digits |
float | 4 bytes | the same, about 7 digits; rarely worth using |
bool with true and false comes from #include <stdbool.h>. Underneath, false is 0 and anything else is true.
sizeof#
sizeof tells you how many bytes a type or variable uses on your machine:
printf("%zu\n", sizeof(int)); // usually 4
printf("%zu\n", sizeof(long long)); // 8
%zu is the placeholder for the size type that sizeof produces.
Overflow#
An int has a largest value, INT_MAX from <limits.h>, which is 2147483647. Go past it and the result is wrong without any warning:
int big = 2147483647;
big = big + 1; // undefined behaviour: in practice usually -2147483648
This is the single most common source of wrong answers in C. When values can approach a billion, or you add many of them up, or multiply two of them, use long long:
long long total = 0;
total += 1000000000LL * 3; // 3000000000, fits
The LL suffix makes the literal itself a long long, so the multiplication happens in 64 bits.
Characters are numbers#
A char stores a small integer, the character's code. That makes arithmetic on characters useful:
char c = '7';
int digit = c - '0'; // 7
char lower = 'b';
int index = lower - 'a'; // 1
char upper = lower - 32; // 'B' in ASCII; toupper() from <ctype.h> is clearer
Single quotes are one char; double quotes are a string. 'A' and "A" are different things.
Constants#
const int DAYS_IN_WEEK = 7;
#define MAX_STUDENTS 100
const makes a variable read-only. #define is a text substitution done before compiling; it is common in older code and for array sizes.
Converting between types#
Mixing types converts the narrower one automatically, but integer division happens before any conversion:
int a = 7, b = 2;
double wrong = a / b; // 3.0: the division was between ints
double right = (double) a / b; // 3.5
int truncated = (int) 3.9; // 3: the fraction is dropped, not rounded
(double) a is a cast: an explicit conversion.
Key points#
- Declare a type for every variable, and always give it a starting value.
intoverflows past about 2.1 billion; uselong longfor large values.charis a small number, soc - '0'andc - 'a'are everyday tricks.- Dividing two ints throws the fraction away; cast first to keep it.
Next: operators, including a few that C has and many languages do not.