What are Variables?
A variable is a named storage location in memory that holds a value which can be modified during program execution.
Variable Concept
┌─────────────────────────────────────────┐
│ MEMORY │
├─────────────────────────────────────────┤
│ │
│ Variable: age │
│ ┌───────────────┐ │
│ │ 25 │ ← Value │
│ └───────────────┘ │
│ Address: 0x7ffd5c │
│ Type: int (4 bytes) │
│ │
│ Variable: name │
│ ┌───────────────────────┐ │
│ │ "Alice" │ ← Value │
│ └───────────────────────┘ │
│ Address: 0x7ffd60 │
│ Type: string │
│ │
└─────────────────────────────────────────┘
Key Properties of Variables
| Property |
Description |
| Name |
Identifier to access the variable |
| Type |
Determines what kind of data it holds |
| Value |
The actual data stored |
| Address |
Location in memory |
| Size |
Amount of memory used |
| Scope |
Where the variable is accessible |
| Lifetime |
How long the variable exists |
Variable Declaration and Initialization
Declaration Syntax
type variableName; // Declaration only
type variableName = value; // Declaration with initialization
type variableName(value); // Constructor initialization
type variableName{value}; // Uniform/brace initialization (C++11)
Examples
// Declaration only (uninitialized - dangerous!)
int count;
// Declaration with initialization
int age = 25;
double price = 19.99;
char grade = 'A';
bool active = true;
// Multiple declarations
int x, y, z; // Three uninitialized ints
int a = 1, b = 2, c = 3; // Three initialized ints
// Uniform initialization (C++11) - preferred
int width{100};
double height{50.5};
string name{"Alice"};
Initialization Methods Compared
int a = 10; // Copy initialization
int b(10); // Direct initialization
int c{10}; // Uniform/brace initialization (C++11)
int d = {10}; // Copy list initialization (C++11)
// Brace initialization prevents narrowing conversions
int x = 3.14; // OK but loses precision (x = 3)
int y{3.14}; // ERROR! Narrowing conversion not allowed
Uninitialized Variables - Danger!
int x; // x contains garbage/random value
cout << x; // Undefined behavior!
// Always initialize:
int x = 0; // Now safe
int y{}; // Zero-initialized
Fundamental Data Types
C++ provides several fundamental (built-in) data types:
┌──────────────────────────────────────────────────────────┐
│ C++ FUNDAMENTAL TYPES │
├──────────────────────────────────────────────────────────┤
│ │
│ Integer Types Floating-Point Types │
│ ├── short ├── float │
│ ├── int ├── double │
│ ├── long └── long double │
│ └── long long │
│ │
│ Character Types Other Types │
│ ├── char ├── bool │
│ ├── wchar_t └── void │
│ ├── char16_t │
│ └── char32_t │
│ │
└──────────────────────────────────────────────────────────┘
Type Sizes (Typical on 64-bit systems)
| Type |
Size (bytes) |
Range |
char |
1 |
-128 to 127 |
short |
2 |
-32,768 to 32,767 |
int |
4 |
-2.1 billion to 2.1 billion |
long |
8 |
-9.2 quintillion to 9.2 quintillion |
long long |
8 |
Same as long |
float |
4 |
±3.4 × 10³⁸ (7 digits precision) |
double |
8 |
±1.7 × 10³⁰⁸ (15 digits precision) |
bool |
1 |
true or false |
Checking Type Sizes
#include <iostream>
using namespace std;
cout << "Size of int: " << sizeof(int) << " bytes" << endl;
cout << "Size of double: " << sizeof(double) << " bytes" << endl;
Integer Types
Available Integer Types
short shortNum = 32767; // At least 16 bits
int regularNum = 2147483647; // At least 16 bits (usually 32)
long longNum = 2147483647L; // At least 32 bits
long long veryLongNum = 9223372036854775807LL; // At least 64 bits
Signed vs Unsigned
// Signed (default) - can be negative
int signedNum = -100; // OK
signed int explicitSigned = -100; // Same thing
// Unsigned - only positive values (0 and above)
unsigned int positiveOnly = 100; // OK
unsigned int overflow = -1; // Wraps to maximum value!
// Unsigned doubles the positive range
// unsigned int: 0 to 4,294,967,295
// signed int: -2,147,483,648 to 2,147,483,647
Fixed-Width Integer Types (C++11)
#include <cstdint>
int8_t tiny = 127; // Exactly 8 bits
int16_t small = 32767; // Exactly 16 bits
int32_t medium = 2147483647; // Exactly 32 bits
int64_t large = 9223372036854775807; // Exactly 64 bits
uint8_t uTiny = 255; // Unsigned 8 bits
uint16_t uSmall = 65535; // Unsigned 16 bits
uint32_t uMedium = 4294967295; // Unsigned 32 bits
uint64_t uLarge = 18446744073709551615ULL; // Unsigned 64 bits
Integer Literals
int decimal = 255; // Decimal
int octal = 0377; // Octal (starts with 0)
int hex = 0xFF; // Hexadecimal (starts with 0x)
int binary = 0b11111111; // Binary (C++14, starts with 0b)
// Suffixes
long l = 100L; // Long
unsigned u = 100U; // Unsigned
unsigned long ul = 100UL; // Unsigned long
long long ll = 100LL; // Long long
// Digit separators (C++14)
int million = 1'000'000;
long long big = 9'223'372'036'854'775'807LL;
Floating-Point Types
Types and Precision
| Type |
Size |
Precision |
Range |
float |
4 bytes |
~7 digits |
±3.4 × 10³⁸ |
double |
8 bytes |
~15 digits |
±1.7 × 10³⁰⁸ |
long double |
8-16 bytes |
~18-21 digits |
Platform dependent |
float f = 3.14f; // Note the 'f' suffix
double d = 3.14159265358979; // Default for decimals
long double ld = 3.14159265358979323846L; // 'L' suffix
Precision Issues
// Floating-point numbers have limited precision
float f = 0.1f + 0.2f;
cout << (f == 0.3f); // May print 0 (false)!
// Use tolerance for comparisons
bool equal = abs(f - 0.3f) < 0.0001f; // Better approach
Special Values
#include <cmath>
#include <limits>
double inf = numeric_limits<double>::infinity();
double negInf = -numeric_limits<double>::infinity();
double nan = numeric_limits<double>::quiet_NaN();
// Checking special values
isfinite(1.0); // true
isinf(inf); // true
isnan(nan); // true
Scientific Notation
double avogadro = 6.022e23; // 6.022 × 10²³
double planck = 6.626e-34; // 6.626 × 10⁻³⁴
float electron = 9.109e-31f; // With float suffix
Character Types
The char Type
char letter = 'A'; // Single quotes for char
char digit = '7';
char newline = '\n'; // Escape sequence
char null = '\0'; // Null character
ASCII Values
Characters are stored as integers:
char a = 'A'; // Actually stores 65
char b = 65; // Same as 'A'
cout << a << endl; // Prints: A
cout << (int)a << endl; // Prints: 65
// Character arithmetic
char upper = 'A';
char lower = upper + 32; // 'a' (ASCII math)
Common ASCII Values
| Character |
ASCII |
Character |
ASCII |
| '0'-'9' |
48-57 |
'A'-'Z' |
65-90 |
| 'a'-'z' |
97-122 |
Space |
32 |
| '\n' |
10 |
'\t' |
9 |
Wide and Unicode Characters
wchar_t wide = L'A'; // Wide character (2-4 bytes)
char16_t utf16 = u'A'; // UTF-16 character (C++11)
char32_t utf32 = U'A'; // UTF-32 character (C++11)
char8_t utf8 = u8'A'; // UTF-8 character (C++20)
// Wide string
wchar_t wstr[] = L"Hello";
Boolean Type
The bool Type
bool isActive = true;
bool hasPermission = false;
// In C++, non-zero is true, zero is false
bool a = 1; // true
bool b = 0; // false
bool c = -1; // true (any non-zero)
bool d = 3.14; // true
Boolean in Conditions
bool loggedIn = true;
if (loggedIn) {
cout << "Welcome!" << endl;
}
// Explicit comparison is redundant:
if (loggedIn == true) // Works, but unnecessary
if (loggedIn) // Preferred
Boolean Operators
bool a = true, b = false;
// Logical AND
bool andResult = a && b; // false
// Logical OR
bool orResult = a || b; // true
// Logical NOT
bool notResult = !a; // false
// Comparison operators return bool
bool isEqual = (5 == 5); // true
bool isGreater = (5 > 3); // true
Type Modifiers
Modifier Keywords
| Modifier |
Effect |
signed |
Can hold negative values (default for int) |
unsigned |
Only non-negative values |
short |
Smaller size |
long |
Larger size |
const |
Value cannot change |
volatile |
Value may change unexpectedly |
mutable |
Can be modified in const context |
Examples
// Size modifiers
short int small = 100; // At least 16 bits
long int big = 100000; // At least 32 bits
long long int huge = 1e18; // At least 64 bits
// Simplified (int is implied)
short s = 100;
long l = 100000;
long long ll = 1e18;
// Combining modifiers
unsigned long ul = 4000000000UL;
unsigned long long ull = 18000000000000000000ULL;
Type Conversion
Implicit Conversion (Automatic)
// Promotion: smaller type to larger type (safe)
int i = 100;
long l = i; // int to long
double d = i; // int to double
// Narrowing: larger type to smaller (may lose data)
double pi = 3.14159;
int truncated = pi; // 3 (decimal lost!)
// Integer promotion in expressions
short a = 10, b = 20;
auto result = a + b; // Result is int, not short
Explicit Conversion (Casting)
// C-style cast (avoid in C++)
int i = (int)3.14; // Old style
// C++ function-style cast
int j = int(3.14); // Slightly better
// C++ named casts (preferred)
double d = 3.14;
int k = static_cast<int>(d); // Safest, most readable
C++ Cast Types
// static_cast - compile-time checked conversions
double d = 3.14;
int i = static_cast<int>(d);
// dynamic_cast - runtime checked (for polymorphism)
Derived* dp = dynamic_cast<Derived*>(basePtr);
// const_cast - remove or add const
const int* cp = &x;
int* p = const_cast<int*>(cp);
// reinterpret_cast - low-level reinterpretation
int* ip = reinterpret_cast<int*>(0x12345678);
Conversion Hierarchy
Promotion Order (implicit):
bool → char → short → int → long → long long → float → double → long double
When types mix in expressions, smaller types promote to larger.
Constants and Literals
Defining Constants
// const keyword (compile-time or runtime)
const int MAX_SIZE = 100;
const double PI = 3.14159265359;
const char NEWLINE = '\n';
// constexpr (compile-time only, C++11)
constexpr int BUFFER_SIZE = 1024;
constexpr double E = 2.71828;
// #define (preprocessor, avoid in C++)
#define OLD_STYLE_CONSTANT 100 // Not recommended
const vs constexpr
// const - may be initialized at runtime
const int x = getUserInput(); // OK
// constexpr - must be known at compile time
constexpr int y = 10 * 5; // OK
constexpr int z = getUserInput(); // ERROR!
// constexpr functions (C++11)
constexpr int square(int n) {
return n * n;
}
constexpr int result = square(5); // Computed at compile time
Literal Types
// Integer literals
42 // int
42L // long
42LL // long long
42U // unsigned int
42UL // unsigned long
42ULL // unsigned long long
// Floating-point literals
3.14 // double (default)
3.14f // float
3.14L // long double
// Character literals
'A' // char
L'A' // wchar_t
u'A' // char16_t
U'A' // char32_t
// String literals
"Hello" // const char[]
L"Hello" // const wchar_t[]
u8"Hello" // const char[] (UTF-8)
u"Hello" // const char16_t[]
U"Hello" // const char32_t[]
R"(raw string)" // Raw string literal
Auto and Type Inference
The auto Keyword (C++11)
// Compiler deduces the type
auto i = 42; // int
auto d = 3.14; // double
auto c = 'A'; // char
auto s = "Hello"; // const char*
auto str = string("Hello"); // string
// Useful for complex types
auto it = myVector.begin(); // vector<int>::iterator
auto result = calculate(); // Whatever calculate() returns
When to Use auto
// Good uses:
auto iter = myMap.find("key"); // Complex iterator type
auto lambda = [](int x) { return x * 2; }; // Lambda type
auto ptr = make_unique<MyClass>(); // Smart pointer
// Avoid when type isn't obvious:
auto x = getValue(); // What type is x? Not clear!
int x = getValue(); // Better - explicit type
decltype (C++11)
int x = 5;
decltype(x) y = 10; // y is int (same type as x)
// Get return type of expression
decltype(x + 1.0) z; // z is double
// Useful in templates
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}
Recommended Conventions
1. Always Initialize Variables
// Bad
int count; // Uninitialized!
cout << count; // Undefined behavior
// Good
int count = 0; // Initialized
int count{}; // Zero-initialized (C++11)
2. Choose Appropriate Types
// For loop counters
for (size_t i = 0; i < container.size(); ++i)
// For small numbers
int age = 25;
// For money (consider fixed-point)
long cents = 1999; // $19.99 as cents
// For measurements
double distance = 5.5;
3. Use const for Unchanging Values
// Magic numbers are bad
area = 3.14159 * r * r; // What is 3.14159?
// Use named constants
const double PI = 3.14159;
area = PI * r * r; // Much clearer!
4. Prefer Brace Initialization
// Prevents accidental narrowing
int x{3.14}; // Error! Narrowing detected
// Prevents unintended conversions
int y{}; // Guaranteed zero initialization
5. Use Fixed-Width Types When Size Matters
#include <cstdint>
// For binary protocols
uint32_t packetId;
int16_t signedValue;
// For file formats
uint8_t byteData;
6. Be Careful with Unsigned Types
unsigned int x = 5;
unsigned int y = 10;
// This is NOT -5, it wraps around!
unsigned int diff = x - y; // Very large positive number!
// Better: use signed when subtraction is possible
int diff = static_cast<int>(x) - static_cast<int>(y);
Summary
| Concept |
Description |
| Variable |
Named memory location storing a value |
| Type |
Determines what data can be stored |
| int |
Whole numbers (typically 4 bytes) |
| double |
Decimal numbers (typically 8 bytes) |
| char |
Single characters (1 byte) |
| bool |
true/false values |
| const |
Unchangeable value |
| auto |
Compiler-deduced type |
| Initialization |
Setting initial value (always do this!) |
| Casting |
Converting between types |
Cheat Sheet
// Declaration and initialization
int age = 25;
double price{19.99};
char grade = 'A';
bool active = true;
const int MAX = 100;
auto value = calculate();
// Type sizes
sizeof(int) // 4 bytes (typical)
sizeof(double) // 8 bytes
// Casting
static_cast<int>(3.14) // Result: 3
Previous: Input/Output | Next: Operators