Data Types
Every value in C++ has a type that decides how much memory it uses, what range of values it can hold, and which operations make sense. In this lesson you'll meet the full set of fundamental types, learn how big each one is, and avoid the classic traps of overflow and floating-point rounding.
Learn Data Types in our free C++ course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 Real-World Analogy
Think of types as differently sized buckets . A char is a thimble (1 byte) that holds a single drop. An int is a coffee mug (4 bytes). A long long is a bucket (8 bytes) that holds far more. A double is also a bucket but it's built to hold decimals precisely. Pour too much into a bucket and it doesn't just spill on the floor — it wraps around to the bottom , which is exactly what integer overflow does. Choosing the right-sized bucket up front prevents nasty surprises.
📊 The Fundamental Types
Type
Holds
Typical Size
Approx Range
bool
true / false
1 byte
2 values
char
One character
-128..127
int
Whole numbers
4 bytes
±2.1 billion
long long
Big whole numbers
8 bytes
±9.2 quintillion
float
Decimals (~7 digits)
±3.4e38
double
Decimals (~15 digits)
±1.7e308
The C++ standard only guarantees minimum sizes; these are the common sizes on a 64-bit desktop. Use sizeof to check on your own machine.
1. The Fundamental Types in Action
Let's declare one of each and print it. Notice char uses single quotes, bool prints as 1 or 0 , and the f suffix on a float literal and the LL suffix on a long long literal pin the value to that exact type.
2. Measuring Size & Range
sizeof tells you how many bytes a type occupies, and the <climits> and <limits> headers expose each type's minimum and maximum value. Knowing the range matters because a value that exceeds it doesn't error — it silently wraps.
3. Overflow: When a Bucket Runs Out
Add 1 to the largest possible int and it wraps around to the most negative value. For signed integers this is actually undefined behavior — the compiler is free to do anything — so never rely on it. For unsigned integers the wrap is well-defined and predictable.
4. The Floating-Point Trap
Decimals like 0.1 can't be stored exactly in binary, so arithmetic introduces tiny rounding errors. cout hides them by rounding to 6 digits, but they're really there. The rule: never compare two doubles with == . Instead check that their difference is smaller than a tiny tolerance (an "epsilon").
5. auto & Literal Suffixes
auto lets the compiler deduce a variable's type from its initializer — with zero runtime cost. The type it picks depends on the literal: 10 is an int , 2.5 is a double , and suffixes like LL , u , and f nudge it toward a specific type.
Now you try. Fill in the blanks below with the right type or value:
🧩 Reorder Challenge
These lines compute a percentage and print it, but they're scrambled. Put them in the correct order so the program compiles and prints Pass rate: 75% .
Why: the #include must come before main . Inside main , the two int variables are declared first, then percent uses them — and the 100.0 forces double division so we get 75 , not integer-truncated 0 . The print and return 0; come last, and the closing brace ends the function.
🧠 Quick Recall
Predict the output before revealing each answer.
3 3.5 — 7 / 2 is integer division (remainder dropped), but 7.0 / 2 is double division.
2 — a bool promotes to int in arithmetic, so true + true is 1 + 1 .
4294967295 — unsigned subtraction wraps around to the maximum value rather than going negative.
Pro Tips
- 💡 Default to int and double : they cover the vast majority of cases. Reach for long long only when a value might exceed ~2 billion.
- 💡 Never == two doubles: compare fabs(a - b) < 1e-9 instead.
- 💡 Avoid mixing signed and unsigned: in comparisons the signed value is converted to unsigned, turning -1 into a huge positive number.
- 💡 Force decimal division: write 100.0 * a / b , not 100 * a / b , when you want a fractional result.
Common Errors (and the fix)
- Silent overflow: storing 3000000000 in an int wraps to a negative number. Use long long for large values.
- Comparing doubles with ==: 0.1 + 0.2 == 0.3 is false . Use an epsilon comparison.
- Integer division surprise: 5 / 2 is 2 . Make one side a decimal: 5.0 / 2 .
- Signed/unsigned mismatch: looping for (unsigned i = 5; i >= 0; --i) never ends because i wraps instead of going below 0.
📋 Quick Reference
Holds / Range
true / false (prints 1 / 0)
one character, -128..127
whole numbers, ±2.1 billion
big whole numbers, ±9.2 quintillion
decimals ~7 digits, ±3.4e38
decimals ~15 digits, ±1.7e308
unsigned int
non-negative, 0..4294967295
sizeof(T)
—
bytes a type uses (a size_t)
auto x = ...;
deduce type from initializer (compile time)
5000000000LL
LL suffix → long long literal
7u / 0.5f
u → unsigned, f → float literal
7 / 2
integer division → 3 (use 7.0 / 2 for 3.5)
numeric_limits<int>::max()
largest value of a type (from <limits>)
fabs(a - b) < 1e-9
compare doubles instead of ==
Frequently Asked Questions
Mini-Challenge: Storage Report
Pick the right type for each value, and remember to force double division when converting bytes to megabytes. Run it and match the expected output in the comments.
🎉 Lesson Complete
- ✅ Fundamental types: bool , char , int , long long , float , double
- ✅ sizeof gives byte sizes; <limits> gives ranges
- ✅ Signed overflow is undefined behavior; unsigned wraps predictably
- ✅ Never compare doubles with == — use an epsilon
- ✅ auto deduces the type at compile time; suffixes LL / u / f pick a type
- ✅ Next lesson: Input & Output — read from cin and format with cout
Practice quiz
Which type is guaranteed to be at least 64 bits for very large whole numbers?
- int
- short
- long long
- byte
Answer: long long. long long is at least 64 bits, holding values up to about 9.2 quintillion.
What does sizeof actually return?
- The value of a variable
- The number of bytes a type occupies
- The number of bits
- The maximum value of a type
Answer: The number of bytes a type occupies. sizeof gives the number of bytes a type or object occupies, as a size_t.
What happens when you add 1 to the maximum value of a signed int?
- It stays at the maximum
- It is undefined behavior (typically wraps to the minimum)
- It throws an exception
- It becomes 0
Answer: It is undefined behavior (typically wraps to the minimum). Signed integer overflow is undefined behavior; in practice it often wraps to the most negative value.
Why should you never compare two doubles with == ?
- == is too slow
- Binary rounding means they may differ slightly
- doubles cannot be compared at all
- == only works on ints
Answer: Binary rounding means they may differ slightly. Values like 0.1 have no exact binary form, so tiny rounding errors make == unreliable; compare against an epsilon.
What does an unsigned int print for (0u - 1)?
- -1
- 0
- 4294967295
- It throws an error
Answer: 4294967295. Unsigned subtraction wraps around cleanly to the maximum value, 4294967295.
What type does 'auto big = 5000000000LL;' deduce?
- int
- double
- long long
- unsigned
Answer: long long. The LL suffix pins the literal to long long, so auto deduces long long.
What is the typical size of a double on a 64-bit desktop?
- 2 bytes
- 4 bytes
- 8 bytes
- 16 bytes
Answer: 8 bytes. double is typically 8 bytes (and int is typically 4).
How much runtime cost does 'auto' add compared to writing the type by hand?
- A small constant cost
- Zero — it is resolved at compile time
- It doubles compile time only
- It allocates extra memory
Answer: Zero — it is resolved at compile time. auto is deduced at compile time and produces identical machine code — zero runtime cost.
What does cout print for (7 / 2) followed by (7.0 / 2)?
- 3.5 and 3.5
- 3 and 3.5
- 3 and 3
- 4 and 3.5
Answer: 3 and 3.5. 7 / 2 is integer division (3); 7.0 / 2 is double division (3.5).
How can you store a value like 3000000000 without silent overflow?
- Use int
- Use char
- Use long long
- Use bool
Answer: Use long long. 3000000000 exceeds int's ~2.1 billion range; use long long for large values.
Continue this course
- Previous: Variables
- Next: Input & Output (cin & cout)