📚
C++ Fundamentals
Master the core concepts of C++ programming
Basic Syntax and Structure
Hello World and Basic Structure
#include <iostream> // Preprocessor directive #include <string> #include <vector> using namespace std; // Using directive (optional) // Function declaration void greetUser(const string& name); int main() { // Output to console cout << "Hello, World!" << endl; // Variables and data types int age = 25; // Integer double height = 5.9; // Double precision floating point char grade = 'A'; // Character bool isStudent = true; // Boolean string name = "Alice"; // String (C++ string class) // Constants const double PI = 3.14159; // Compile-time constant const int MAX_SIZE = 100; // Auto keyword (C++11) - type deduction auto temperature = 98.6; // Deduced as double auto count = 42; // Deduced as int // Input from user cout << "Enter your name: "; string userName; getline(cin, userName); // Read entire line including spaces // Function call greetUser(userName); return 0; // Return success status } // Function definition void greetUser(const string& name) { cout << "Welcome to C++, " << name << "!" << endl; } // Compilation commands: // g++ -o program program.cpp (basic compilation) // g++ -std=c++17 -o program program.cpp (with C++17 standard)
💡 C++ Key Concepts
- • Compiled Language: C++ code is compiled to machine code for fast execution
- • Header Files: Use
#include
to include libraries and declarations - • Namespaces: Organize code and avoid naming conflicts
- • Strong Typing: Variables must be declared with specific types
Data Types and Variables
Fundamental Data Types
#include <iostream> #include <climits> // For type limits #include <string> int main() { // Integer types short shortNum = 32767; // 16-bit: -32,768 to 32,767 int regularNum = 2000000; // 32-bit: -2^31 to 2^31-1 long longNum = 9000000000L; // 64-bit on most systems long long bigNum = 9000000000LL; // At least 64-bit // Unsigned integers (only positive values) unsigned int positiveNum = 4000000000U; unsigned char byte = 255; // 0 to 255 // Floating point types float decimal = 3.14f; // 32-bit floating point double preciseDecimal = 3.14159; // 64-bit floating point long double extendedDecimal = 3.141592653589793L; // Extended precision // Character types char letter = 'A'; // Single character wchar_t wideChar = L'Ω'; // Wide character char16_t utf16Char = u'€'; // UTF-16 character (C++11) char32_t utf32Char = U'🚀'; // UTF-32 character (C++11) // Boolean bool isTrue = true; // true or false // String types string cppString = "Hello C++"; // C++ string class const char* cString = "Hello C"; // C-style string (null-terminated) // Type information cout << "Size of int: " << sizeof(int) << " bytes" << endl; cout << "Size of double: " << sizeof(double) << " bytes" << endl; cout << "Max int value: " << INT_MAX << endl; cout << "Min int value: " << INT_MIN << endl; // Type casting int intValue = 100; double doubleValue = static_cast<double>(intValue); // Safe casting int backToInt = static_cast<int>(3.14); // Explicit casting // C-style casting (not recommended) double oldStyleCast = (double)intValue; // Const and constexpr const int ARRAY_SIZE = 10; // Runtime constant constexpr int COMPILE_TIME = 20; // Compile-time constant (C++11) return 0; }
Arrays and Pointers
#include <iostream> #include <array> // For std::array (C++11) #include <vector> // For std::vector int main() { // C-style arrays int numbers[5] = {1, 2, 3, 4, 5}; // Fixed size array int matrix[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}}; // 2D array // Array access cout << "First element: " << numbers[0] << endl; cout << "Array size: " << sizeof(numbers)/sizeof(numbers[0]) << endl; // C++11 std::array (safer alternative) array<int, 5> modernArray = {10, 20, 30, 40, 50}; cout << "Modern array size: " << modernArray.size() << endl; // Dynamic arrays with std::vector vector<int> dynamicArray = {100, 200, 300}; dynamicArray.push_back(400); // Add element dynamicArray.pop_back(); // Remove last element cout << "Vector size: " << dynamicArray.size() << endl; // Iterating through arrays cout << "C-style array: "; for (int i = 0; i < 5; i++) { cout << numbers[i] << " "; } cout << endl; // Range-based for loop (C++11) cout << "Modern array: "; for (const auto& value : modernArray) { cout << value << " "; } cout << endl; // Pointers int value = 42; int* ptr = &value; // Pointer to int cout << "Value: " << value << endl; cout << "Address: " << &value << endl; cout << "Pointer: " << ptr << endl; cout << "Dereferenced: " << *ptr << endl; // Pointer arithmetic int arr[] = {10, 20, 30, 40, 50}; int* arrPtr = arr; // Points to first element cout << "First element: " << *arrPtr << endl; cout << "Second element: " << *(arrPtr + 1) << endl; cout << "Third element: " << arrPtr[2] << endl; // Array notation // Null pointers int* nullPtr = nullptr; // C++11 null pointer if (nullPtr == nullptr) { cout << "Pointer is null" << endl; } // References (aliases) int original = 100; int& ref = original; // Reference to original ref = 200; // Changes original cout << "Original after reference change: " << original << endl; return 0; }
Control Flow
Conditionals and Loops
#include <iostream> #include <vector> #include <string> int main() { int score = 85; // If-else statements if (score >= 90) { cout << "Grade: A" << endl; } else if (score >= 80) { cout << "Grade: B" << endl; } else if (score >= 70) { cout << "Grade: C" << endl; } else { cout << "Grade: F" << endl; } // Ternary operator string result = (score >= 60) ? "Pass" : "Fail"; cout << "Result: " << result << endl; // Switch statement char grade = 'B'; switch (grade) { case 'A': cout << "Excellent!" << endl; break; case 'B': cout << "Good job!" << endl; break; case 'C': cout << "Average" << endl; break; default: cout << "Need improvement" << endl; break; } // For loops cout << "Counting 1 to 5: "; for (int i = 1; i <= 5; i++) { cout << i << " "; } cout << endl; // Range-based for loop (C++11) vector<string> fruits = {"apple", "banana", "orange"}; cout << "Fruits: "; for (const auto& fruit : fruits) { cout << fruit << " "; } cout << endl; // While loop int count = 0; cout << "While loop: "; while (count < 3) { cout << count << " "; count++; } cout << endl; // Do-while loop int number = 0; cout << "Do-while loop: "; do { cout << number << " "; number++; } while (number < 2); cout << endl; // Break and continue cout << "Break and continue example: "; for (int i = 0; i < 10; i++) { if (i == 3) continue; // Skip iteration when i is 3 if (i == 7) break; // Exit loop when i is 7 cout << i << " "; } cout << endl; // Nested loops cout << "Multiplication table (3x3):" << endl; for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { cout << i * j << " "; } cout << endl; } return 0; }
Functions
Function Declaration and Definition
#include <iostream> #include <vector> #include <string> using namespace std; // Function declarations (prototypes) void printMessage(); int add(int a, int b); double calculateArea(double length, double width); void printArray(const int arr[], int size); void modifyValue(int& value); // Pass by reference void printVector(const vector<int>& vec); // Pass by const reference // Function overloading - same name, different parameters int multiply(int a, int b); double multiply(double a, double b); int multiply(int a, int b, int c); // Default parameters void greet(const string& name, const string& greeting = "Hello"); // Template function (generic programming) template<typename T> T getMax(T a, T b) { return (a > b) ? a : b; } int main() { // Function calls printMessage(); int result = add(5, 3); cout << "5 + 3 = " << result << endl; double area = calculateArea(5.0, 3.0); cout << "Area: " << area << endl; // Array parameter int numbers[] = {1, 2, 3, 4, 5}; printArray(numbers, 5); // Pass by reference int value = 10; cout << "Before modification: " << value << endl; modifyValue(value); cout << "After modification: " << value << endl; // Vector parameter vector<int> vec = {10, 20, 30, 40}; printVector(vec); // Function overloading cout << "Int multiply: " << multiply(4, 5) << endl; cout << "Double multiply: " << multiply(4.5, 2.0) << endl; cout << "Triple multiply: " << multiply(2, 3, 4) << endl; // Default parameters greet("Alice"); // Uses default greeting greet("Bob", "Good morning"); // Custom greeting // Template function cout << "Max of 10, 20: " << getMax(10, 20) << endl; cout << "Max of 3.14, 2.71: " << getMax(3.14, 2.71) << endl; cout << "Max of 'a', 'z': " << getMax('a', 'z') << endl; return 0; } // Function definitions void printMessage() { cout << "Hello from a function!" << endl; } int add(int a, int b) { return a + b; } double calculateArea(double length, double width) { return length * width; } void printArray(const int arr[], int size) { cout << "Array elements: "; for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; } void modifyValue(int& value) { value *= 2; // Modify the original variable } void printVector(const vector<int>& vec) { cout << "Vector elements: "; for (const auto& element : vec) { cout << element << " "; } cout << endl; } // Function overloading implementations int multiply(int a, int b) { return a * b; } double multiply(double a, double b) { return a * b; } int multiply(int a, int b, int c) { return a * b * c; } void greet(const string& name, const string& greeting) { cout << greeting << ", " << name << "!" << endl; }
Memory Management
Dynamic Memory Allocation
#include <iostream> #include <memory> // For smart pointers (C++11) using namespace std; int main() { // Stack vs Heap int stackVariable = 42; // Stored on stack (automatic cleanup) // Dynamic allocation with new/delete (C-style, not recommended) int* heapVariable = new int(42); // Stored on heap cout << "Heap value: " << *heapVariable << endl; delete heapVariable; // Manual cleanup required heapVariable = nullptr; // Avoid dangling pointer // Dynamic array allocation int size = 5; int* dynamicArray = new int[size]{1, 2, 3, 4, 5}; cout << "Dynamic array: "; for (int i = 0; i < size; i++) { cout << dynamicArray[i] << " "; } cout << endl; delete[] dynamicArray; // Use delete[] for arrays dynamicArray = nullptr; // Smart Pointers (C++11) - Automatic memory management // unique_ptr - Exclusive ownership unique_ptr<int> uniquePtr = make_unique<int>(100); cout << "Unique ptr value: " << *uniquePtr << endl; // Automatically deleted when uniquePtr goes out of scope // unique_ptr with arrays unique_ptr<int[]> uniqueArray = make_unique<int[]>(5); for (int i = 0; i < 5; i++) { uniqueArray[i] = i * 10; } cout << "Unique array: "; for (int i = 0; i < 5; i++) { cout << uniqueArray[i] << " "; } cout << endl; // shared_ptr - Shared ownership shared_ptr<int> sharedPtr1 = make_shared<int>(200); shared_ptr<int> sharedPtr2 = sharedPtr1; // Share ownership cout << "Shared ptr value: " << *sharedPtr1 << endl; cout << "Reference count: " << sharedPtr1.use_count() << endl; // weak_ptr - Non-owning observer weak_ptr<int> weakPtr = sharedPtr1; if (auto locked = weakPtr.lock()) { // Check if still valid cout << "Weak ptr value: " << *locked << endl; } // Memory leaks example (what NOT to do) /* void memoryLeak() { int* ptr = new int(42); // Forgot to call delete - MEMORY LEAK! return; // ptr goes out of scope, memory not freed } */ // RAII (Resource Acquisition Is Initialization) principle // Resources are automatically managed by constructors/destructors return 0; } // Custom class demonstrating RAII class RAIIExample { private: int* data; size_t size; public: // Constructor - acquire resource RAIIExample(size_t s) : size(s) { data = new int[size]; cout << "Resource acquired" << endl; } // Destructor - release resource ~RAIIExample() { delete[] data; cout << "Resource released" << endl; } // Copy constructor (Rule of 3/5) RAIIExample(const RAIIExample& other) : size(other.size) { data = new int[size]; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } } // Assignment operator RAIIExample& operator=(const RAIIExample& other) { if (this != &other) { delete[] data; // Clean up existing resource size = other.size; data = new int[size]; for (size_t i = 0; i < size; i++) { data[i] = other.data[i]; } } return *this; } // Move constructor (C++11) RAIIExample(RAIIExample&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; other.size = 0; } // Move assignment operator (C++11) RAIIExample& operator=(RAIIExample&& other) noexcept { if (this != &other) { delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; } return *this; } };
⚠️ Memory Management Best Practices
- • Prefer smart pointers over raw pointers for dynamic allocation
- • Follow RAII principle - resources managed by constructors/destructors
- • Every new must have a delete (if not using smart pointers)
- • Use containers like vector instead of raw arrays when possible
- • Set pointers to nullptr after deletion to avoid dangling pointers