Your AI powered learning assistant

C++ Full Course for free ⚡️

1.C++ tutorial for beginners 👨‍

00:00:00

C++: Speed, Control, and Real‑World Uses C++ delivers high performance and works close to hardware, making it ideal for advanced graphics, video editing software, embedded systems, and especially video games. As a middle‑level language, it balances human readability with low‑level control. Higher‑level languages are easier to write but typically slower; C and C++ demand more care yet run fast. There is a learning curve, but the payoff in capability is worth it.

Set Up Your Editor and Compiler Use a text editor or IDE such as VS Code, Code::Blocks, or even Notepad; in VS Code install the C/C++ and Code Runner extensions. You also need a compiler that translates source to machine code: GCC on Linux or Windows, and Clang on macOS. On Linux and macOS, installation is quick—verify with gcc --version or clang after installing the toolchain. On Windows, install MSYS2/MinGW‑w64 with pacman, add the mingw64/bin path to your environment variables, and confirm with g++ --version.

First Program: main, iostream, and Console Output Include the iostream header to gain basic input/output operations. Define int main() { ... } as the program entry point and return 0 to signal success (non‑zero indicates an issue). Use std::cout with << to print text, and end lines with std::endl or the newline character '\n'. The newline character is faster; std::endl also flushes the output buffer. Add single‑line comments with // and multi‑line comments with /* ... */.

Variables and Core Data Types Declare first, then assign, or initialize in one step, e.g., int x = 5. Use int for whole numbers, double for numbers with decimals, char for a single character in single quotes, bool for true/false, and std::string for sequences of text. Assigning a decimal to an int truncates the fractional part. Mix text and variables in output with std::cout, minding spaces to produce readable messages.

Lock Values with const Prefix const to make a value read‑only, preventing accidental modification. Constants are commonly named in uppercase, e.g., const double PI = 3.14159. Attempting to assign to a const triggers a compile error, protecting critical values. Typical constants include mathematical values (like PI), physical constants (like light speed), or fixed settings (such as screen width and height).

Avoid Name Collisions with Namespaces Namespaces allow entities with the same name to coexist when they live in different scopes. Access a specific one with the scope resolution operator ::, such as first::x or second::x. Writing using namespace lets you omit the prefix for that namespace’s entities. Avoid using namespace std because it contains many entities and increases the chance of conflicts; prefer qualifying (std::cout, std::string) or selective using declarations.

Simplify Types with typedef and using Create type aliases to shorten long or complex types and improve readability. For example, alias std::string as text_t or int as number_t to clarify intent. typedef works, but using is preferred today, especially with templates. A common convention appends _t to alias names.

Compute with Arithmetic Operators Use +, -, *, and / for basic math, and compound assignments like += or -= to update a variable. ++ and -- increment or decrement by one, often seen in loops. Integer division discards the fractional part; doubles retain it. The modulus operator % returns remainders and is handy for even/odd checks. Respect precedence: parentheses first, then multiplication/division, then addition/subtraction.

Control Conversions Between Types Implicit conversion happens automatically, such as assigning 3.14 to an int and getting 3. Explicit conversion precedes a value with the target type in parentheses, e.g., (int)3.14. Converting integers to char maps through character codes, so 100 becomes 'd'. When computing percentages like correct/questions*100, cast to double to avoid truncating with integer division.

Get User Input Safely Read basic values with std::cin >> var, and capture full lines (with spaces) using std::getline(std::cin, str). In VS Code, enable Code Runner’s Run in Terminal to allow typing input. When mixing std::cin and std::getline, consume leftover whitespace with std::ws to avoid an immediate empty read. Then echo inputs back with std::cout to confirm what was captured.

Use Math Utilities; Compute a Hypotenuse std::max and std::min return the larger or smaller of two values. Include to access pow, sqrt, abs, round, ceil, and floor for common numeric tasks. Read sides a and b, then compute a right triangle’s hypotenuse with c = sqrt(pow(a, 2) + pow(b, 2)). The intermediate steps can be written explicitly or composed inline in a single expression.

Branch Logic with if/else Use comparison operators to test conditions and execute code only when they’re true. Gate access by checking age >= 18, and handle edge cases like negative ages or very large ages with else if branches. Remember == tests equality, while = assigns. Order your conditions carefully, since the first true branch executes and the rest are skipped.

Switch Cases for Clear Multiway Choices A switch compares one value against many labeled cases and is cleaner than long else‑if chains. Break after each case to prevent fall‑through, and provide a default for invalid inputs. Map 1–12 to month names or interpret letter grades A–F with tailored messages. The same pattern cleanly powers a simple calculator that performs +, -, *, or / based on a single operator character.

Write Compact Conditions with the Ternary Operator Replace if/else with condition ? expr_if_true : expr_if_false when a brief decision suffices. Show pass/fail based on a grade threshold in one line. Detect even/odd numbers by checking number % 2 and selecting the appropriate message. Ternaries also nest inside stream output to print one of two strings inline.

Combine Conditions with &&, ||, and ! && requires all conditions to be true, such as keeping temperature within a comfortable range. || fires when any condition is true, useful for flagging values outside a range. ! negates a condition, turning true to false and vice versa. Together they model everyday logic like weather checks and power states succinctly.

Convert Between Fahrenheit and Celsius Let users choose a target unit with 'F' or 'C' (case‑insensitive), then input the temperature. Convert Celsius to Fahrenheit with 1.8*temp + 32, or Fahrenheit to Celsius with (temp - 32) / 1.8. Print the converted value with the correct unit. If the unit is invalid, prompt the user to enter only C or F.

Master Common String Methods length() returns the number of characters, and empty() lets you detect missing input. clear() wipes the content, while append() adds text to the end, such as building a username. at(index) retrieves a specific character; insert(index, str) adds a substring at a position; find(' ') locates the first space. erase(start, end) removes a segment (the end is not inclusive), and indexes start at 0.

Repeat Work with while and do‑while A while loop repeats as long as its condition remains true, perfect for validating input until it’s acceptable. Ensure there’s a way to change the condition, or it becomes an infinite loop. A do‑while runs the block once before checking, ideal when you must prompt at least once, like asking for a positive number. This pattern also suits replay prompts in simple games.

Count and Iterate with for Loops The for loop bundles initialization, condition, and update for a fixed number of repetitions. Count upward or downward, and change the step size with expressions like i += 2 or i -= 2. Display sequences such as 1 to 10, or countdowns to 0. Execute follow‑up code after the loop, such as printing a final message.

Break and Continue to Control Loops break exits a loop early, stopping further iterations; you also use it inside switch statements. continue skips just the current iteration and moves to the next one. For example, while counting to 20, skip 13 without halting the loop by using continue. Choose break when the loop’s work is done and continue when only a single pass should be omitted.

Build Patterns with Nested Loops Place one loop inside another to handle rows and columns. The outer loop controls the number of lines, and the inner loop prints the contents of each line. After the inner loop, output a newline to start the next row. Use this to print a rectangle of a chosen symbol given user‑specified rows and columns.

Generate Random Dice, Seeds, and Events Seed the pseudo‑random number generator with srand(time(0)) to vary results each run, then get values from rand(). Constrain ranges with modulus and shift to 1..N (e.g., rand()%6 + 1 for a die), and roll multiple dice by generating multiple values. Use the random result in a switch to pick prizes or other events from a set of cases. These numbers are pseudo‑random but sufficient for simple games.

Use break to prevent switch fall-through in random events Generate a random prize and select it with a switch. Without break statements, execution falls through and awards multiple prizes. Add break after each case to ensure only one outcome. This pattern suits simple random event features in games.

Build a number guessing game with do-while and rand Seed the generator with srand(time(NULL)) and set num = rand()%100 + 1. Loop with do-while until guess equals num, prompting the user each time. Increment a tries counter and print “Too high” or “Too low” based on comparisons. On a correct guess, announce success and display the number of tries.

Functions encapsulate reusable actions Define a void function that prints the “Happy Birthday” lyrics. Call it from main as many times as needed to reuse the logic. A function has a return type, name, parentheses, and a body in braces. Invoking it executes that block without duplicating code.

Declare function prototypes to satisfy top-down compilation Programs are read top-down, so calls before a definition need a declaration. Place a function prototype (return type and signature) above main when defining the function later. This resolves “not declared in this scope” errors. The declaration’s return type and parameters must match the definition.

Share data with functions via arguments and parameters Local variables in one function aren’t visible in another. Pass values like name and age as arguments in the call, and receive them with matching-typed parameters. Parameter names can differ from the caller’s variable names. Once received, the function can use them to personalize output.

Return values from functions with the correct type Use return to send a value back to the call site. Compute an area with double square(length) returning length*length, and a volume with double cube(length) returning length*length*length. For strings, return first + ' ' + second to form a full name. Change the function’s return type from void to the type of value returned.

Overload functions by varying parameter lists Create multiple bake_pizza versions: one with no parameters, one with a single topping, and one with two toppings. The shared name is legal because each has a unique parameter list. The combination of name and parameters is the function signature. Calls resolve to the version whose signature matches the arguments.

Understand local vs global scope and the scope resolution operator Local variables exist only within their function or block; identical names can be reused in different scopes. Globals are defined outside all functions and are accessible everywhere, but should be avoided to reduce namespace pollution and increase safety. When both exist, the local shadows the global. Use ::variable to access the global explicitly.

Create a menu-driven banking app with validation Implement show_balance(balance), deposit(), and withdraw(balance) and drive them with a switch inside a do-while until Exit. Format currency with iomanip: fixed and setprecision(2). Accept deposits only if amount > 0; refuse withdrawals that exceed balance or are negative, and update and display balance after each operation. Handle bad input by calling cin.clear() then fflush(stdin) to reset and flush the input buffer.

Rock–Paper–Scissors with input checks and randomness Prompt the player in a loop until a valid choice (r, p, s) is entered. Display choices with showChoice using a switch. Generate the computer’s choice with srand(time(0)) and rand()%3 + 1 mapped to R, P, or S. Decide outcomes in choose_winner by switching on the player’s pick and comparing against the computer’s.

Arrays store indexed, same-typed values Transform a single variable into an array with brackets and initialize with brace-enclosed values. Printing an array name yields its memory address; access elements by zero-based index. Arrays are homogenous and can be reassigned by index. If not initializing immediately, declare the size and assign later.

Use sizeof to inspect memory and count array elements sizeof returns the size in bytes of variables and types, like 8 for double. A string shows a fixed size (e.g., 32 bytes) because it holds an address to its text. For arrays, divide sizeof(array) by sizeof(one element) to get the element count. The trick works for char arrays and even arrays of strings.

Iterate arrays safely with index-based for loops Loop from i = 0 while i < sizeof(arr)/sizeof(arr[0]) to traverse all elements. This avoids hardcoding lengths and adapts automatically if the array size changes. Use the index to access arr[i] each iteration. Apply the pattern to arrays of strings or characters alike.

Simplify traversal with the for-each loop The for-each loop reduces syntax: specify the element type and a name, then iterate over the array. It cleanly prints or processes every element from start to finish. It’s less flexible than an indexed loop—no reverse or skipping—but ideal for straightforward passes. Use it with strings or ints to display contents.

Pass arrays to functions and include the size When passed to a function, an array decays to a pointer and its size is lost. Compute the size in the caller and pass it as an extra argument. Inside the function, loop up to that size to process elements, such as summing prices for a total. Return the result to the caller.

Perform a linear search and return the index or -1 Scan from the first element to the last, comparing each to the target. If a match is found, return the current index; otherwise return -1 as a sentinel. Report either the found index or that the item isn’t present. Adapt the function to strings and use getline to accept inputs with spaces.

Sort with bubble sort using nested loops and swaps Repeat passes over the array, comparing adjacent elements and swapping when the left is greater than the right. The inner loop can stop at size - i - 1 because the largest elements bubble to the end. Use a temp variable to perform the swap. Flip the comparison to sort in descending order.

Fill array ranges with std::fill Initialize many elements at once by calling fill(begin_address, end_address, value). Use arr and arr + size to cover the whole array, or slice it to fill halves or thirds with different strings. Define a constant size and reuse it to avoid magic numbers. Adjust ranges like size/2 or size/3 to target segments.

Collect user input into a fixed-size array with an early exit Prompt for items with getline, showing a 1-based prompt number while storing at zero-based indices. Allow quitting by entering Q: read into a temp variable, break if it’s Q, otherwise assign it to the array. When displaying results, skip empty slots by looping until the current element is not empty. Remember arrays are static in size, so unused capacity remains.

Model grids with 2D arrays and nested loops Declare a two-dimensional array with [rows][cols] and initialize inner arrays for each row. Access elements with two indices: row then column. Compute row and column counts using sizeof tricks on the outer and first inner array. Use nested loops where the outer controls rows and the inner iterates columns to print the matrix.

Assemble a quiz game with questions, options, and an answer key Store questions in a string array and options in a 2D string array with four columns per question. Keep correct answers in a char array, iterate through questions, and display options. Read a guess, convert it to uppercase, and compare against the answer key to award points or show the correct answer. Afterward, print results, total correct, question count, and a percentage using a cast to avoid integer division.

Inspect memory addresses with the address-of operator Use &variable to print a variable’s memory address, shown in hexadecimal and varying per run. Different data types occupy different byte counts, which affects address spacing. A bool typically sits one byte from its neighbor, while an int may be four bytes away. Seeing where values live helps prepare for pointers.

Swapping Succeeds Only When Passing by Reference Swapping two variables inside a function fails when parameters are passed by value, because only copies are exchanged while the originals remain unchanged. Adding & to the parameter types passes references (memory addresses), so assignments inside the function write directly to the caller’s variables. Printing the addresses of x and y in main and inside the function reveals four distinct locations with pass-by-value and matching locations with pass-by-reference. Use pass-by-reference when a function must modify external data; pass-by-value when you intentionally want isolated copies.

Const Parameters Safeguard Function Inputs Prefixing parameters with const makes them read-only within the function, improving safety and signaling intent. With pass-by-value, const mainly documents that originals won’t be changed; with references and pointers, it prevents modifying the referenced data or the pointer’s target. Mirroring const in both the declaration and definition clarifies usage for other programmers.

Luhn Algorithm Validates Credit Card Numbers Double every second digit from right to left, splitting any two-digit result into its separate digits and summing them. Add that to the sum of the untouched digits in the odd positions from the right. If the grand total is divisible by 10, the number passes validation; otherwise, it fails.

Implementing Luhn in C++ with String Digits Iterate the number string from right to left, treating it like a char array, and convert each character to an integer by subtracting '0'. Double the even-position digits and split tens and ones with number % 10 + (number / 10) % 10, while odd-position digits are added as-is. Combine both sums and test result % 10 == 0 to decide validity.

Pointers Store Addresses and Expose Values A pointer holds the memory address of another variable, obtained with &, and the value at that address is accessed with *. The pointer’s type must match the pointee’s type, and dereferencing lets you read and write through the address. Printing a pointer shows an address; dereferencing shows the underlying value.

Arrays Decay to Pointers and First-Element Access An array name already acts as an address, so assigning it to a pointer doesn’t require an additional &. Printing the array or its pointer yields a memory address, and dereferencing it returns the first element. This behavior lets functions receive array parameters as pointers without extra conversion.

Null Pointers Signal Unassigned Addresses The nullptr literal marks a pointer that points to nothing, which is safer than leaving it uninitialized. Before dereferencing, check against nullptr to ensure an address was actually assigned, especially in scenarios like dynamic allocation. Dereferencing a null or uninitialized pointer leads to undefined behavior.

Tic-Tac-Toe: Board, Moves, and Win/Tie Logic Represent the grid as a nine-element char array passed to functions, where it decays to a pointer for board drawing and updates. The player selects positions 1–9, mapped to indices 0–8, and input is validated so only empty spots accept markers. The computer seeds a PRNG, picks random cells until an empty one appears, and after each move the game checks rows, columns, and diagonals for three equal non-spaces. If no winning line exists and no spaces remain, it declares a tie and ends the loop with a closing message.

Dynamic Memory with new and delete Use new to allocate objects in the heap and store the returned address in a pointer. Assign or read the heap value by dereferencing the pointer, and free the memory with delete when it’s no longer needed. Neglecting delete risks memory leaks.

Dynamic Arrays Sized by User Input Ask the user for a size, allocate with new T[size], and treat the result as a normal array for indexing and iteration. Read values into the array in a loop, display them, and release the block with delete[]. This approach adapts to unknown sizes at runtime.

Recursion as Repeated Single Steps Replace loops with a function that calls itself while a base case eventually halts further calls. A walking example prints a step and recurses with steps–1 until reaching zero; skipping the base case causes infinite recursion and a stack overflow. Recursion often yields simpler code, at the cost of extra memory and overhead.

Factorial: Iterative vs Recursive Trade-offs The iterative factorial multiplies 1 through n with an accumulator and returns the result. The recursive version returns n * factorial(n–1) when n > 1, with 1 as the base result, producing the same value using a call stack. Choose recursion for clarity and iteration for speed and memory efficiency.

Function Templates Remove Redundant Overloads By replacing concrete types with a template parameter like typename T, one max function handles ints, doubles, and chars. The compiler instantiates specific versions as needed, so you maintain a single implementation. This template acts like a reusable cookie cutter for function shapes.

Mixing Types in Templates with Auto Return When argument types differ, introduce a second template parameter, such as typename U, so the function accepts both. Set the return type to auto, allowing the compiler to deduce a type that preserves values like 2.1 instead of truncating. Additional parameters (V, W, X, …) extend this pattern to more diverse combinations.

Structs Group Mixed-Type Members A struct bundles related members of different types under one name, like a Student with string name, double GPA, and bool enrolled. Create multiple instances, assign members, and access them with the dot operator, with booleans displaying as 1 for true and 0 for false. Members can also carry default values, such as enrolled defaulting to true.

Passing Structs by Value or by Reference Passing a struct to a function by value creates a copy, so modifications affect only the duplicate and its address differs from the caller’s. Passing by reference with & lets the function update the original, as in repainting a Car’s color. Printing addresses before and inside the function confirms whether a copy or the original is being used.

Enums Provide Named Integer Options for Switch Switch statements require integral cases, so replace strings with enums that map readable names to integers. Define enum Day { Sunday=0, Monday=1, …, Saturday=6 } and switch on those names or their numeric equivalents. Enum variables hold exactly one of the predefined options, and unassigned entries default to sequential integers starting at zero.

Objects Combine Attributes and Methods A class serves as a blueprint for objects that have attributes and can perform actions via methods. A Human carries name, occupation, and age, and can eat, drink, and sleep; a Car holds make, model, year, and color, and can accelerate and brake. Instances receive their own attribute values while sharing method behavior.

Constructors Assign Attributes on Instantiation A constructor shares the class name and runs automatically to initialize attributes with arguments at creation time. A Student constructor receives name, age, and GPA and assigns them, using this-> when parameter names match attribute names; alternatively, distinct parameter names avoid this. A Car constructor similarly captures make, model, year, and color at object creation.

Overloaded Constructors Enable Flexible Object Creation Multiple constructors with the same name but different parameters let objects be built with varying data. A Pizza can be created with no toppings, one topping, or two toppings by providing matching constructors, each assigning its specific members. The compiler selects the appropriate constructor based on the argument list.

Getters and Setters Enforce Encapsulation Make sensitive attributes private and expose controlled access through getters and setters. A Stove hides its temperature, exposes a getter to read it, and a setter that clamps input to a safe range of 0–10 before assignment. Calling the setter inside the constructor applies the same validation at creation time.

Inheritance Reuses Code Across Related Classes A child class inherits attributes and methods from a parent, avoiding duplication and centralizing shared behavior. Dog and Cat derive from Animal, gaining alive and eat while adding bark and meow; changing the parent’s eat message updates both. Shape provides area and volume, while Cube and Sphere add side or radius and compute surface area and volume in their constructors, noting to use 3.0 to avoid integer division.