All Courses
Foundations

Variables and Data Types in C++


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