C++ for Beginners Part 2: Variables, Data Types, and Operators
Explore C++'s fundamental data types — int, float, double, char, and bool — plus how to declare variables, use constants, and apply arithmetic, comparison, and logical operators. Includes a detailed look at type conversion and the sizeof operator.
C++ for Beginners: A Complete Guide
An eight-part beginner-friendly journey through C++: from writing your first program and understanding variables, through control flow, functions, and arrays, to the heart of C++ — pointers, classes, inheritance, and polymorphism. Each article is self-contained and builds on the previous, giving you both a quick reference and a progressive path to mastery.
- 1 C++ for Beginners Part 1: Your First C++ Program
- 2 C++ for Beginners Part 2: Variables, Data Types, and Operators
- 3 C++ for Beginners Part 3: Control Flow — Conditions and Loops
- 4 C++ for Beginners Part 4: Functions
- 5 C++ for Beginners Part 5: Arrays, Strings, and std::vector
Table of Contents
- Variables: named boxes in memory
- Fundamental data types
- Integers
- Floating-point numbers
- Characters
- Boolean
- Declaring without initialising (don't do this)
- Constants
- const
- constexpr
- auto — let the compiler infer the type
- The sizeof operator
- Arithmetic operators
- Integer division gotcha
- Increment / Decrement
- Compound assignment
- Comparison operators
- Logical operators
- Type conversion
- Implicit (automatic)
- Explicit cast
- Putting it together: temperature converter
- Key takeaways
Variables: named boxes in memory
A variable is a named location in RAM that holds a value. In C++ you must declare a variable's type before using it — the compiler needs to know how much memory to reserve and what operations are legal.
int age = 25; // 4 bytes, whole number
double price = 9.99; // 8 bytes, decimal number
char grade = 'A'; // 1 byte, single character
bool isOpen = true; // 1 byte, true or false
The pattern is always: type name = value;
Fundamental data types
Integers
| Type | Typical size | Range |
|---|---|---|
short |
2 bytes | −32 768 to 32 767 |
int |
4 bytes | −2 147 483 648 to 2 147 483 647 |
long |
4 or 8 bytes | depends on platform |
long long |
8 bytes | ±9.2 × 10¹⁸ |
Add unsigned to any integer type to get only non-negative values and double the positive range:
unsigned int score = 0; // 0 to 4 294 967 295
unsigned long long bigNum; // 0 to 1.8 × 10¹⁹
Floating-point numbers
| Type | Size | Precision |
|---|---|---|
float |
4 bytes | ~7 decimal digits |
double |
8 bytes | ~15 decimal digits |
long double |
16 bytes | ~18–19 decimal digits |
float pi_f = 3.14159f; // 'f' suffix marks it as float
double pi_d = 3.14159265358979;
Use double by default. float saves memory but loses precision — useful mainly in graphics or embedded work.
Characters
char letter = 'B'; // single quotes, single character
char newline = '
'; // escape sequences count as one char
Under the hood, char is just an 8-bit integer. 'A' is stored as 65 (its ASCII value).
char c = 'A';
std::cout << c; // A
std::cout << (int)c; // 65
Boolean
bool loggedIn = false;
bool hasError = true;
std::cout << loggedIn; // 0
std::cout << hasError; // 1
C++ prints 0 for false and 1 for true.
Declaring without initialising (don't do this)
int x;
std::cout << x; // undefined behaviour — could print anything
Always initialise your variables. Uninitialized variables contain whatever bytes happened to be at that memory address. Use = 0, = false, or brace-init:
int x = 0;
int y{}; // value-initializes to 0 (modern C++ style)
Constants
const
A const variable cannot be changed after initialization:
const double PI = 3.14159265358979;
const int MAX_USERS = 1000;
PI = 3.0; // error: assignment of read-only variable
constexpr
constexpr means the value is known at compile time, allowing the compiler to substitute it directly into the generated code (no memory overhead at runtime):
constexpr int BOARD_SIZE = 8; // chess board
constexpr double GRAVITY = 9.80665; // m/s²
Use constexpr for values that are truly constant and known ahead of time.
auto — let the compiler infer the type
auto score = 100; // int
auto price = 4.99; // double
auto initial = 'X'; // char
auto enabled = true; // bool
auto is not "no type" — the compiler deduces the exact type from the right-hand side. It's useful for long type names but can hurt readability if overused.
The sizeof operator
sizeof returns the number of bytes occupied by a type or variable:
std::cout << sizeof(int) << "
"; // 4
std::cout << sizeof(double) << "
"; // 8
std::cout << sizeof(char) << "
"; // 1
int arr[10];
std::cout << sizeof(arr); // 40 (10 × 4)
Arithmetic operators
| Operator | Meaning | Example |
|---|---|---|
+ |
Addition | 3 + 4 → 7 |
- |
Subtraction | 10 - 3 → 7 |
* |
Multiplication | 3 * 4 → 12 |
/ |
Division | 10 / 3 → 3 (integer!) |
% |
Modulo (remainder) | 10 % 3 → 1 |
Integer division gotcha
When both operands are integers, / performs integer division and discards the remainder:
int a = 10, b = 3;
std::cout << a / b; // 3, not 3.333...
To get floating-point division, cast at least one operand:
std::cout << (double)a / b; // 3.33333...
std::cout << a / (double)b; // 3.33333...
Increment / Decrement
int n = 5;
n++; // n is now 6 (post-increment)
++n; // n is now 7 (pre-increment)
n--; // n is now 6
The difference between n++ and ++n matters when the expression is used as a value:
int a = 5;
int b = a++; // b = 5, a = 6 (b gets value BEFORE increment)
int c = ++a; // c = 7, a = 7 (c gets value AFTER increment)
Compound assignment
int x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
x /= 4; // x = 6
x %= 4; // x = 2
Comparison operators
Produce true or false:
| Operator | Meaning |
|---|---|
== |
Equal to |
!= |
Not equal to |
< |
Less than |
> |
Greater than |
<= |
Less than or equal |
>= |
Greater than or equal |
int age = 20;
std::cout << (age >= 18); // 1 (true)
std::cout << (age == 21); // 0 (false)
Logical operators
Combine boolean expressions:
| Operator | Meaning | Example |
|---|---|---|
&& |
AND — both must be true | (a > 0 && b > 0) |
|| |
OR — at least one true | (a > 0 || b > 0) |
! |
NOT — flips true/false | !loggedIn |
int age = 17;
bool hasParentPermission = true;
bool canEnter = (age >= 18) || hasParentPermission;
std::cout << canEnter; // 1 (true)
Type conversion
Implicit (automatic)
C++ promotes narrower types to wider ones automatically:
int i = 5;
double d = i; // int → double, fine
double x = 3.7;
int y = x; // double → int, truncates to 3 — data loss!
The compiler may warn about the second case with -Wconversion.
Explicit cast
double pi = 3.14159;
int rounded = (int)pi; // C-style cast
int rounded2 = static_cast<int>(pi); // C++ style (preferred)
static_cast is preferred in C++ because it's searchable and explicit about your intent.
Putting it together: temperature converter
#include <iostream>
int main() {
double celsius;
std::cout << "Enter temperature in Celsius: ";
std::cin >> celsius;
double fahrenheit = (celsius * 9.0 / 5.0) + 32.0;
std::cout << celsius << "°C = " << fahrenheit << "°F
";
return 0;
}
Notice 9.0 and 5.0 — using integer literals 9/5 would give 1 due to integer division, producing a wrong result.
Key takeaways
- C++ has distinct integer, floating-point, character, and boolean types.
- Always initialise variables — uninitialized values are undefined behaviour.
- Use
constorconstexprfor values that shouldn't change. /on two integers does integer division — cast todoublewhen you need decimals.static_cast<T>()is the C++ way to convert between types explicitly.
Next up: control flow — making decisions and repeating actions with if/else, switch, and loops.