Skip to main content
    Courses/C++/Variables & Data Types

    Lesson 2 • Beginner

    Variables & Data Types

    By the end of this lesson you'll be able to store text, numbers, and true/false values in C++, choose the right type, convert safely between them, and read input from the user — the foundation of every C++ program you'll ever write.

    What You'll Learn

    • Use the fundamental types: int, double, float, char, bool, std::string
    • Declare and initialize variables, including modern brace init int x{5}
    • Let the compiler infer types with auto
    • Lock values with const and constexpr
    • Understand signed vs unsigned and type sizes with sizeof
    • Convert types safely with static_cast and read input with std::cin

    💡 Real-World Analogy

    A variable is a labelled container in a kitchen. A jar labelled "Sugar" (string) holds text; a measuring cup labelled "Cups" (int) holds whole numbers; a scale labelled "Weight" (double) holds decimals. Each container only holds one kind of thing — you can't pour flour into a liquid measuring cup. C++ is statically typed, which means every variable's type is fixed when you declare it and the compiler checks it before your program ever runs. That strictness is a feature: it catches whole classes of mistakes early.

    📊 The Core Data Types

    TypeHoldsSizeExample
    intWhole numbers4 bytesint age = 25;
    doubleDecimals (~15 digits)8 bytesdouble h = 1.75;
    floatDecimals (~7 digits)4 bytesfloat t = 36.6f;
    charOne character1 bytechar g = 'A';
    booltrue / false1 bytebool ok = true;
    std::stringTextvariesstring n = "Al";

    Notice string uses "double quotes" but char uses 'single quotes' — mixing these up is the #1 beginner error, so it's worth burning in now. (string lives in the <string> header.)

    1. Declaring & Initializing Variables

    Every variable needs a type and a name, and you usually give it a value on the same line: type name = value;. Use descriptive camelCase names like firstName or totalPrice — code is read far more often than it's written, so a clear name pays for itself. Read this worked example, run it, then check the output against the comments.

    Worked example: six fundamental types

    Read every comment, run it, and check the output matches.

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        // A variable = a named box that stores ONE type of value.
        // Pattern:  type  name  =  value;
        int age = 25;              // whole number (no decimal point)
        double price = 19.99;      // decimal number (~15 digits, the default)
        float temperature = 36.6f; // decimal, less precision -> note the 'f'
        char grade = 'A';          // a SINGLE character -> 'single quotes'
        bool isStudent = true;     // true
    ...

    There's more than one way to give a variable its first value. The modern brace initializationint x{5} — is preferred because it refuses to silently lose data (it blocks "narrowing", like squeezing 3.9 into an int). And auto lets the compiler pick the type for you from the value on the right.

    Worked example: =, braces, and auto

    Compare copy init, brace init, and auto type inference.

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        // Three ways to create a variable:
        int a = 5;        // copy initialization (the classic =)
        int b{10};        // brace initialization -> the modern, safer way
        int c;            // declare only -> value is GARBAGE until you set it
        c = 15;           // now c is safe to use
    
        // auto: let the compiler work out the type from the value.
        auto x = 42;          // x is int (because 42 is a whole number)
    
    ...

    Your turn. The program below is almost complete — fill in the three blanks marked ___ using the hints in the comments, then run it.

    🎯 Your turn: declare three variables

    Fill in the ___ blanks, then check your output against the expected lines.

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        // 🎯 YOUR TURN — replace each ___ then press "Try it Yourself".
    
        // 1) Make an int called "year" set to the current year
        int year = ___;        // 👉 a whole number, e.g. 2026
    
        // 2) Make a string called "city" set to a city name
        string city = ___;     // 👉 text in "double quotes"
    
        // 3) Make a double called "price" set to 9.99
        double price = ___;    // 👉 a decimal number
    
        // These lines a
    ...

    2. Constants, Signedness & Sizes

    Some values should never change — a tax rate, a maximum number of lives, pi. Mark them const and the compiler will reject any attempt to reassign them. constexpr goes one step further: the value must be known at compile time, which lets the compiler use it as a fixed size or array length. Numbers are also signed by default (they can be negative); marking one unsigned drops the negatives and reaches a bigger positive range with the same memory. sizeof tells you exactly how many bytes a type uses.

    Worked example: const, constexpr, unsigned, sizeof

    See read-only values, signedness, and memory sizes.

    Try it Yourself »
    C++
    #include <iostream>
    using namespace std;
    
    int main() {
        // const = a value that can NEVER change after it is set.
        const double PI = 3.14159265;
        // PI = 3.14;  // ERROR: assignment of read-only variable 'PI'
    
        // constexpr = known at COMPILE time (even stronger than const).
        constexpr int MAX_PLAYERS = 100;
    
        double radius = 5.0;
        double area = PI * radius * radius;   // 78.5398
        cout << "Area: " << area << endl;
        cout << "Max players: " << MAX_PLAYERS << endl;
    
        /
    ...

    3. Type Conversion & Casting

    Sometimes a value is the wrong type and you need to convert it. Implicit conversion happens automatically when it's safe (an int fits inside a double). When the conversion can lose data — like double to int — C++ may still do it but the decimals just vanish. To convert deliberately you use static_cast<type>(value), which states your intent clearly and is far safer than old C-style (int) casts. The classic trap: dividing two int values gives an int result.

    Worked example: implicit, narrowing & static_cast

    See safe vs lossy conversion and the integer-division trap.

    Try it Yourself »
    C++
    #include <iostream>
    using namespace std;
    
    int main() {
        // Implicit conversion — automatic and SAFE (no data lost).
        int whole = 10;
        double asDecimal = whole;   // int -> double happens for you
        cout << "Implicit: " << asDecimal << endl;  // 10
    
        // Narrowing — automatic but LOSES data (the decimals vanish).
        double pi = 3.14159;
        int truncated = pi;         // 3  (chopped, NOT rounded)
        cout << "Truncated: " << truncated << endl; // 3
    
        // Integer division trap: both
    ...

    Now you try. The two values below are int, so a plain / would chop the decimals off. Cast one side to double so the answer keeps its fraction:

    🎯 Your turn: cast to keep the decimals

    Wrap one value in static_cast<double>(...) so division is accurate.

    Try it Yourself »
    C++
    #include <iostream>
    using namespace std;
    
    int main() {
        // 🎯 YOUR TURN — both numbers are ints, so plain division truncates.
        int distanceKm = 7;
        int hours = 2;
    
        // 1) Cast distanceKm to a double so the division keeps decimals
        double speed = ___ / hours;   // 👉 static_cast<double>(distanceKm)
    
        cout << distanceKm << "km in " << hours << "h = "
             << speed << " km/h" << endl;
    
        // ✅ Expected output:  7km in 2h = 3.5 km/h
        return 0;
    }

    4. Scope & Reading Input with cin

    Scope is simply where a variable is visible. A variable lives inside the nearest pair of { } braces and disappears at the closing brace — try to use it outside and the compiler won't know what you mean. You read keyboard input with std::cin >> variable: the >> operator pulls what the user typed into your variable, automatically matching the variable's type (a number into an int, a word into a string).

    Worked example: scope and cin

    See block scope, then read a name and birth year from the user.

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        // SCOPE = where a variable is visible. A variable lives inside the
        // nearest { } block and disappears at the closing brace.
        int outer = 1;
        {
            int inner = 2;          // 'inner' only exists in this block
            cout << outer << " " << inner << endl; // 1 2  (both visible)
        }
        // cout << inner;  // ERROR: 'inner' was not declared in this scope
    
        // cin reads typed input INTO a variable using
    ...

    🔎 Deep Dive: auto vs spelling out the type

    auto asks the compiler to deduce the type from the value: auto city = string("London"); is exactly a string. It's still strongly typed — once deduced, the type is fixed. Use auto to cut noise when the type is obvious or very long, but prefer the explicit type when it makes beginner code clearer.

    const and constexpr both mean "do not reassign". const is read-only at run time; constexpr is fixed at compile time. Constants are written in UPPER_SNAKE_CASE by convention so they stand out.

    auto greeting = string("Hi"); // compiler infers std::string
    const int MAX_LIVES = 3;       // read-only at run time
    constexpr int BOARD = 8;       // known at compile time
    // MAX_LIVES = 5;              // ❌ error: assignment of read-only variable

    Pro Tips

    • 💡 Prefer double over float: double is the default and far more precise; only use float when memory is genuinely tight.
    • 💡 Always initialize: an uninitialized local like int x; holds a garbage value until you assign one. Give every variable a starting value.
    • 💡 Use brace init for safety: int x{5} blocks narrowing conversions that int x = 5.9; would silently allow.
    • 💡 Name things well: totalPrice tells a story; tp or x doesn't.

    Common Errors (and the fix)

    • Uninitialized variable (undefined behaviour): int x; cout << x; prints a random garbage value — and the program's behaviour is undefined. Always initialize: int x = 0; or int x{}.
    • Integer division truncation: cout << 7 / 2; prints 3, not 3.5. Make one side a decimal — 7.0 / 2 — or use static_cast<double>(7) / 2.
    • "narrowing conversion ... inside { }": brace init blocks lossy conversions, so int n{3.9}; won't compile. Use a double, or cast: int n{static_cast<int>(3.9)};.
    • Wrong quotes: "A" (double quotes) is a string; 'A' (single quotes) is a char. Writing char c = "A"; fails to compile because the types don't match.
    • "was not declared in this scope": you used a variable outside the { } block it was declared in. Declare it in an outer scope so it's still visible where you need it.

    📋 Quick Reference

    TaskCodeResult
    Declare integerint x = 10;10
    Brace initint x{5};5 (safe)
    Infer typeauto y = 3.14;double
    Constantconst int MAX = 100;read-only
    Safe caststatic_cast<double>(x)double
    Memory sizesizeof(int)4
    Read inputcin >> age;into age

    Frequently Asked Questions

    Q: When should I use int, double, or float?

    Use int for whole numbers (ages, counts, indexes). Use double for decimals — it is the default floating-point type in C++ and gives about 15 significant digits. Only reach for float when memory is very tight, because it keeps roughly half the precision.

    Q: Why did 7 / 2 give me 3 instead of 3.5?

    Both 7 and 2 are int values, so C++ does integer division and throws away the remainder. Make one side a decimal — 7.0 / 2 — or cast it with static_cast<double>(7) / 2 to get 3.5.

    Q: What is the difference between 'A' and "A"?

    'A' in single quotes is a char — exactly one character. "A" in double quotes is a std::string of length 1. They are different types, so mixing the quotes is a common beginner error.

    Q: Should I use auto for every variable?

    No. auto is great when the type is obvious from the right-hand side or very long to write, but spelling out int or double often makes beginner code clearer. Use auto to remove noise, not to hide what a variable actually is.

    Q: What is the difference between const and constexpr?

    const means the value cannot change after it is set. constexpr is stronger: the value must be known at compile time, so the compiler can bake it in. Use const for read-only values and constexpr for true compile-time constants like a maximum size.

    Mini-Challenge: Profile Card

    No blanks this time — just a brief and a blank canvas (with an outline to keep you on track). Build it, run it, and check your output against the example in the comments. This is exactly the kind of small program real apps are made of.

    🎯 Mini-Challenge: build a profile card

    Declare the variables yourself and print a 4-line profile.

    Try it Yourself »
    C++
    #include <iostream>
    #include <string>
    using namespace std;
    
    int main() {
        // 🎯 MINI-CHALLENGE: Profile card
        // 1. Create variables: name (string), age (int),
        //    heightMeters (double), likesCoding (bool).
        // 2. Print a tidy 4-line profile using cout << ... << endl.
        // 3. BONUS: it is their birthday — add 1 to age with  age = age + 1;
        //    then print "Next year you'll be " << age.
        //
        // ✅ Example output:
        //    Name: Sam
        //    Age: 20
        //    Height: 1.
    ...

    🎉 Lesson Complete

    • ✅ Fundamental types: int, double, float, char, bool, std::string
    • "double quotes" for strings, 'single quotes' for a single char
    • ✅ Brace init int x{5} blocks narrowing; auto infers the type
    • const and constexpr lock values; unsigned drops negatives; sizeof shows bytes
    • ✅ Implicit conversion is automatic; static_cast<type>(x) converts safely and clearly
    • ✅ Variables live inside their { } scope; cin >> reads input into them
    • Next lesson: Operators — do maths, compare values, and combine conditions

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service