Variables, Data Types and printf
How C stores numbers and characters in fixed-size, declared types — and how to print them.
C makes you declare types
In Python you write age = 19 and Python figures out it's a number. C is different and stricter: you must declare what type of data a variable holds before using it. This is called static typing, and while it's more typing up front, it lets the compiler catch mistakes and run faster.
int age = 19; // a whole number
float price = 49.99; // a number with decimals
char grade = 'A'; // a single character (single quotes!)
double pi = 3.14159; // a more precise decimal
Once a variable is declared as an int, it can only ever hold whole numbers. Try to store text in it and the compiler refuses. This rigidity is a feature — it stops a whole category of bugs before your program ever runs.
The core data types and their sizes
Every C type has a fixed size in memory, measured in bytes. This is one of the things C exposes that Python hides:
- int — whole numbers, typically 4 bytes (about ±2 billion)
- float — decimal numbers, 4 bytes, ~6 digits of precision
- double — decimal numbers, 8 bytes, ~15 digits (use this when precision matters)
- char — a single character, 1 byte, written in single quotes like
'A'
You can see the sizes yourself with the sizeof operator:
#include <stdio.h>
int main() {
printf("int: %lu bytes\n", sizeof(int));
printf("double: %lu bytes\n", sizeof(double));
printf("char: %lu bytes\n", sizeof(char));
return 0;
}
Understanding that an int is a fixed box of 4 bytes — and that it can overflow if you exceed its range — is exactly the kind of low-level awareness that makes C such a valuable teacher.
The char type and ASCII
A char holds a single character, but here's the secret: internally it's just a small integer. Each character maps to a number through the ASCII table — 'A' is 65, 'a' is 97, '0' is 48. This means you can do arithmetic on characters:
#include <stdio.h>
int main() {
char letter = 'A';
printf("%c has ASCII value %d\n", letter, letter); // A has ASCII value 65
printf("Next letter: %c\n", letter + 1); // Next letter: B
return 0;
}
This relationship between characters and numbers is hidden in most languages but laid bare in C. It explains how text comparison and case conversion actually work under the hood.
Format specifiers: the printf language
printf uses format specifiers as placeholders, and each type has its own. Get the wrong one and you'll print garbage, so this is worth memorising:
int count = 42;
float pi = 3.14159;
char initial = 'M';
printf("%d\n", count); // %d for int -> 42
printf("%f\n", pi); // %f for float -> 3.141590
printf("%.2f\n", pi); // 2 decimals -> 3.14
printf("%c\n", initial); // %c for char -> M
printf("%s\n", "Hello"); // %s for string -> Hello
You can mix several in one call, and the values are filled in order:
int age = 19;
float height = 5.8;
printf("Age %d, height %.1f feet\n", age, height);
// Age 19, height 5.8 feet
Constants and good naming
When a value should never change, mark it const. The compiler will then refuse any attempt to modify it, protecting you from accidental bugs:
const float PI = 3.14159;
const int MAX_STUDENTS = 60;
// PI = 3.14; // compiler error — can't modify a const
By convention, constants are written in UPPERCASE so they stand out. Regular variables use lowercase descriptive names. Good naming and const together make your intent crystal clear to anyone reading the code — including future you. With types and printing mastered, we're ready to compute and compare values using operators.
Finished "Variables, Data Types and printf"?
Mark this chapter complete so you can pick up exactly where you left off. Your progress saves locally — sign in to sync across devices.
Was this chapter clear?
