System Programming Topic

C++ Arrays, Strings & Pointers

1. Arrays

One-dimensional Arrays

cpp

// Declaration and initialization
int numbers[5];                    // Declaration only (contains garbage)
int scores[5] = {85, 90, 78, 92, 88};  // Declaration with initialization
int marks[] = {95, 87, 92};        // Size automatically calculated (3)
int zeros[10] = {0};               // All elements initialized to 0
int arr[5] = {1, 2};               // First two: 1,2; rest: 0

// Accessing elements
numbers[0] = 10;    // First element (index 0)
numbers[4] = 50;    // Last element (size-1)
int x = numbers[2]; // Read value

// Array size
int size = sizeof(numbers) / sizeof(numbers[0]); // Get array size

Multi-dimensional Arrays

cpp

// 2D Array (Matrix)
int matrix[3][3];  // 3 rows, 3 columns

// Initialization
int grid[2][3] = {
    {1, 2, 3},     // Row 0
    {4, 5, 6}      // Row 1
};

// Accessing elements
grid[0][1] = 10;    // Row 0, Column 1
int value = grid[1][2];  // Row 1, Column 2 = 6

// 3D Array
int cube[2][3][4] = {
    {   // Layer 0
        {1,2,3,4},
        {5,6,7,8},
        {9,10,11,12}
    },
    {   // Layer 1
        {13,14,15,16},
        {17,18,19,20},
        {21,22,23,24}
    }
};

// Looping through arrays
int arr[5] = {1,2,3,4,5};
for(int i = 0; i < 5; i++) {
    cout << arr[i] << " ";
}

// 2D array loop
for(int i = 0; i < 2; i++) {
    for(int j = 0; j < 3; j++) {
        cout << grid[i][j] << " ";
    }
    cout << endl;
}

Array Initialization Methods

cpp

// Different initialization methods
int arr1[5];               // Garbage values
int arr2[5] = {};          // All zeros
int arr3[5] = {0};         // All zeros
int arr4[5] = {1,2,3};     // {1,2,3,0,0}
int arr5[] = {1,2,3,4,5};  // Size = 5

// Designated initializers (C++20)
int arr6[5] = {[0] = 1, [2] = 3, [4] = 5}; // {1,0,3,0,5}

Passing Arrays to Functions

cpp

#include <iostream>
using namespace std;

// Method 1: As pointer (most common)
void printArray(int* arr, int size) {
    for(int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

// Method 2: As array with size
void printArray2(int arr[], int size) {
    for(int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

// Method 3: Fixed-size array (size must match exactly)
void printFixedArray(int (&arr)[5]) {
    for(int i = 0; i < 5; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

// Method 4: Using template for any size
template<size_t N>
void printTemplateArray(int (&arr)[N]) {
    for(size_t i = 0; i < N; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

// Passing 2D array
void print2DArray(int arr[][3], int rows) {
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < 3; j++) {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }
}

int main() {
    int numbers[] = {1,2,3,4,5};
    int matrix[2][3] = {{1,2,3},{4,5,6}};
    
    printArray(numbers, 5);
    printArray2(numbers, 5);
    printFixedArray(numbers);
    printTemplateArray(numbers);
    print2DArray(matrix, 2);
    
    return 0;
}

Array Limitations & Modern Alternatives

cpp

// C++ array limitations:
// 1. Fixed size
// 2. No bounds checking
// 3. Passed as pointer (loses size information)

// Modern alternatives:
#include <array>   // std::array (fixed size)
#include <vector>  // std::vector (dynamic size)

// std::array (C++11)
#include <array>
std::array<int, 5> arr = {1,2,3,4,5};
cout << "Size: " << arr.size() << endl;
cout << "Front: " << arr.front() << endl;
cout << "Back: " << arr.back() << endl;
arr.fill(0);  // Fill all with 0

// std::vector (dynamic array)
#include <vector>
std::vector<int> vec = {1,2,3};
vec.push_back(4);  // Add element
vec.pop_back();    // Remove last

2. Strings

C-style Strings (Character Arrays)

cpp

// C-style strings are null-terminated character arrays
char str1[20];                     // Uninitialized
char str2[20] = "Hello";           // Size 20, content "Hello\0"
char str3[] = "World";             // Size 6 (5 chars + null terminator)
char str4[10] = {'H', 'i', '\0'};  // Manual null termination

// Important: Always include space for null terminator '\0'
char name[6] = "Alice";  // 'A','l','i','c','e','\0'

// String functions from <cstring>
#include <cstring>

char str1[20] = "Hello";
char str2[20] = "World";

strlen(str1);                     // Length: 5
strcpy(str1, str2);               // Copy str2 to str1
strncpy(str1, str2, 3);           // Copy first 3 chars
strcat(str1, str2);               // Concatenate
strcmp(str1, str2);               // Compare: 0=equal, <0=str1<str2, >0=str1>str2
strchr(str1, 'l');                // Find first occurrence of 'l'
strstr(str1, "lo");               // Find substring

// Example usage
char source[] = "Hello World";
char destination[50];

strcpy(destination, source);
cout << destination << endl;  // Hello World

strcat(destination, " C++");
cout << destination << endl;  // Hello World C++

// Compare strings
if(strcmp(source, "Hello World") == 0) {
    cout << "Strings are equal" << endl;
}

// Find character
char* pos = strchr(source, 'W');
if(pos) {
    cout << "Found at position: " << (pos - source) << endl;
}

std::string (Modern C++)

cpp

#include <iostream>
#include <string>
using namespace std;

// Declaration and initialization
string s1;                     // Empty string
string s2 = "Hello";           // From C-string
string s3("World");            // Constructor
string s4 = s2;                // Copy
string s5(5, 'A');             // "AAAAA"
string s6 = {'H', 'i'};        // Initializer list

// Input/Output
string name;
cout << "Enter name: ";
cin >> name;                    // Single word
getline(cin, name);            // Whole line (with spaces)

// Common operations
string str = "Hello World";

// Access
cout << str[0];                // H
cout << str.at(1);             // e (with bounds checking)

// Size
cout << str.length();          // 11
cout << str.size();            // 11
cout << str.empty();           // false

// Modification
str.append(" C++");            // "Hello World C++"
str.push_back('!');            // Add single character
str.insert(5, " beautiful");   // "Hello beautiful World"
str.erase(5, 10);              // Remove 10 chars from position 5
str.replace(6, 5, "C++");      // Replace 5 chars from position 6
str.clear();                   // Make empty

// Concatenation
string s1 = "Hello";
string s2 = "World";
string s3 = s1 + " " + s2;     // "Hello World"
s1 += " C++";                  // Append

// Comparison
if(s1 == s2) cout << "Equal";
if(s1 != s2) cout << "Not equal";
if(s1 < s2)  cout << "s1 < s2";  // Lexicographical

// Substring
string sub = str.substr(6, 5);  // From position 6, 5 chars = "World"
size_t pos = str.find("World"); // Find substring
size_t rpos = str.rfind("l");   // Find last occurrence

// Conversion
string numStr = to_string(123);     // "123"
int num = stoi("456");              // 456
double d = stod("3.14159");         // 3.14159

// Iteration
for(char c : str) {
    cout << c << " ";
}

for(auto it = str.begin(); it != str.end(); ++it) {
    cout << *it << " ";
}

// C-string conversion
const char* cstr = str.c_str();     // Read-only C-string
char buffer[50];
str.copy(buffer, 5, 0);            // Copy 5 chars to buffer

// String streams
#include <sstream>
stringstream ss;
ss << "Age: " << 25 << " Name: " << "John";
string info = ss.str();

String Functions & Methods

cpp

string text = "Hello World Programming";

// Searching
size_t found = text.find("World");     // 6
found = text.find('o');                // 4 (first)
found = text.find('o', 5);             // 7 (from position 5)
found = text.find_first_of("aeiou");   // 1 (first vowel)
found = text.find_last_of("aeiou");    // 21 (last vowel)
found = text.find_first_not_of("Helo "); // 5 (W)

// Replacement
text.replace(6, 5, "C++");            // "Hello C++ Programming"

// Substring extraction
string word = text.substr(6, 5);      // "World"
string suffix = text.substr(6);       // "World Programming"

// Case conversion
#include <algorithm>
#include <cctype>

string mixed = "Hello World";
transform(mixed.begin(), mixed.end(), mixed.begin(), ::toupper);
cout << mixed << endl;                // HELLO WORLD

transform(mixed.begin(), mixed.end(), mixed.begin(), ::tolower);
cout << mixed << endl;                // hello world

// Trimming whitespace
#include <algorithm>
#include <cctype>

string spaced = "  Hello World  ";
// Trim left
spaced.erase(spaced.begin(), find_if(spaced.begin(), spaced.end(),
    [](unsigned char ch) { return !isspace(ch); }));

// Trim right
spaced.erase(find_if(spaced.rbegin(), spaced.rend(),
    [](unsigned char ch) { return !isspace(ch); }).base(), spaced.end());

cout << "[" << spaced << "]" << endl;  // [Hello World]

// Splitting string
vector<string> splitString(const string& str, char delimiter) {
    vector<string> tokens;
    string token;
    stringstream ss(str);
    
    while(getline(ss, token, delimiter)) {
        tokens.push_back(token);
    }
    
    return tokens;
}

string data = "apple,banana,cherry,date";
vector<string> fruits = splitString(data, ',');
// fruits = {"apple", "banana", "cherry", "date"}

3. Pointers

Pointer Basics

cpp

int x = 10;
int* ptr = &x;  // ptr stores address of x

cout << "Value of x: " << x << endl;        // 10
cout << "Address of x: " << &x << endl;     // 0x...
cout << "Value of ptr: " << ptr << endl;    // Same address as &x
cout << "Value at ptr: " << *ptr << endl;   // 10 (dereferencing)

// Modifying through pointer
*ptr = 20;
cout << "x is now: " << x << endl;          // 20

// Pointer declaration styles
int* p1;     // Most common
int * p2;    // Also valid
int *p3;     // Also valid
int* p4, p5; // p4 is pointer, p5 is int (careful!)

// Pointer to different types
double d = 3.14;
double* dptr = &d;

char c = 'A';
char* cptr = &c;

Pointer Arithmetic

cpp

int arr[] = {10, 20, 30, 40, 50};
int* ptr = arr;  // Points to first element

cout << *ptr << endl;    // 10
ptr++;                   // Move to next int
cout << *ptr << endl;    // 20
ptr += 2;                // Move 2 ints forward
cout << *ptr << endl;    // 40
ptr--;                   // Move back
cout << *ptr << endl;    // 30

// Pointer differences
int* ptr1 = &arr[0];
int* ptr2 = &arr[3];
cout << "Difference: " << (ptr2 - ptr1) << endl;  // 3 elements

// Valid operations
int* p = arr;
p++;      // Move to next element
p--;      // Move to previous element
p = p + 3;// Move 3 elements forward
p = p - 2;// Move 2 elements back

// Invalid operations
// p = p * 2;  // Error
// p = p / 2;  // Error
// p = p % 2;  // Error

Pointers & Arrays

cpp

int numbers[5] = {1, 2, 3, 4, 5};
int* ptr = numbers;  // ptr points to first element

// Array name is a pointer to first element
cout << numbers << endl;    // Address of first element
cout << &numbers[0] << endl; // Same address

// Accessing array elements via pointer
cout << *(numbers + 0) << endl;  // 1
cout << *(numbers + 1) << endl;  // 2
cout << *(numbers + 2) << endl;  // 3

// Pointer iteration through array
for(int* p = numbers; p < numbers + 5; p++) {
    cout << *p << " ";
}

// Array of pointers
int a = 10, b = 20, c = 30;
int* ptrArr[3] = {&a, &b, &c};

for(int i = 0; i < 3; i++) {
    cout << *ptrArr[i] << " ";  // 10 20 30
}

// Pointer to array
int (*arrayPtr)[5] = &numbers;  // Pointer to entire array
cout << (*arrayPtr)[2] << endl; // 3

// Dynamic array with pointer
int size = 5;
int* dynamicArray = new int[size];  // Heap allocation
for(int i = 0; i < size; i++) {
    dynamicArray[i] = i * 10;
}
delete[] dynamicArray;  // Don't forget to free!

Pointers to Functions

cpp

#include <iostream>
using namespace std;

// Function prototypes
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }

// Function pointer type
typedef int (*Operation)(int, int);  // Old style
using Operation2 = int(*)(int, int); // Modern (C++11)

int main() {
    // Function pointer declaration
    int (*funcPtr)(int, int);
    
    // Assign function to pointer
    funcPtr = add;
    cout << funcPtr(5, 3) << endl;  // 8
    
    funcPtr = subtract;
    cout << funcPtr(5, 3) << endl;  // 2
    
    // Array of function pointers
    Operation operations[] = {add, subtract, multiply};
    
    for(int i = 0; i < 3; i++) {
        cout << operations[i](10, 5) << endl;
        // 15, 5, 50
    }
    
    // Using with switch
    char op = '+';
    int x = 10, y = 5;
    
    switch(op) {
        case '+': funcPtr = add; break;
        case '-': funcPtr = subtract; break;
        case '*': funcPtr = multiply; break;
    }
    
    cout << "Result: " << funcPtr(x, y) << endl;
    
    return 0;
}

// Callback function example
#include <vector>
#include <algorithm>

void printSquare(int n) {
    cout << n * n << " ";
}

void processNumbers(vector<int> nums, void (*callback)(int)) {
    for(int num : nums) {
        callback(num);
    }
}

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5};
    processNumbers(numbers, printSquare);  // 1 4 9 16 25
    return 0;
}

Null Pointers

cpp

// Old style (avoid in C++)
int* ptr1 = NULL;    // Defined as 0
int* ptr2 = 0;       // Literal 0

// Modern C++ (preferred)
int* ptr3 = nullptr; // C++11

// Checking for null
int* ptr = nullptr;

if(ptr == nullptr) {
    cout << "Pointer is null" << endl;
}

if(!ptr) {  // Shorthand
    cout << "Pointer is null" << endl;
}

// Dereferencing null pointer causes undefined behavior
// DON'T DO THIS:
// int* nullPtr = nullptr;
// *nullPtr = 10;  // CRASH!

// Use case: Optional return
int* findValue(int arr[], int size, int target) {
    for(int i = 0; i < size; i++) {
        if(arr[i] == target) {
            return &arr[i];  // Return address if found
        }
    }
    return nullptr;  // Return null if not found
}

// Smart pointers (C++11) - better alternative
#include <memory>
std::unique_ptr<int> smartPtr = std::make_unique<int>(42);
// Automatically manages memory

Void Pointers

cpp

// void* can point to any data type
int num = 10;
float f = 3.14;
char c = 'A';

void* vptr;

vptr = &num;  // Point to int
cout << *(static_cast<int*>(vptr)) << endl;  // Must cast to use

vptr = &f;    // Point to float
cout << *(static_cast<float*>(vptr)) << endl;

vptr = &c;    // Point to char
cout << *(static_cast<char*>(vptr)) << endl;

// Use case: Generic functions
void printValue(void* ptr, char type) {
    switch(type) {
        case 'i':
            cout << *(static_cast<int*>(ptr)) << endl;
            break;
        case 'f':
            cout << *(static_cast<float*>(ptr)) << endl;
            break;
        case 'c':
            cout << *(static_cast<char*>(ptr)) << endl;
            break;
    }
}

int main() {
    int x = 42;
    float y = 3.14;
    char z = 'X';
    
    printValue(&x, 'i');  // 42
    printValue(&y, 'f');  // 3.14
    printValue(&z, 'c');  // X
    
    return 0;
}

4. References

Reference Variables

cpp

int x = 10;
int& ref = x;  // ref is a reference to x (alias)

cout << "x = " << x << endl;      // 10
cout << "ref = " << ref << endl;  // 10

ref = 20;      // Modify through reference
cout << "x = " << x << endl;      // 20 (x also changed!)

// Must be initialized when declared
int& ref2;     // ERROR: must be initialized

// References are like constant pointers
int y = 30;
// ref = y;     // This reassigns value, not reference itself
// After this, ref still refers to x, x becomes 30

// References to different types
double d = 3.14;
double& dref = d;

string s = "Hello";
string& sref = s;

Pass by Reference

cpp

#include <iostream>
using namespace std;

// Pass by value (copy)
void swapByValue(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    // Changes only affect local copies
}

// Pass by reference
void swapByReference(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
    // Changes affect original variables
}

// Pass by pointer
void swapByPointer(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// Return by reference (careful with scope!)
int& getElement(int arr[], int index) {
    return arr[index];  // Return reference to array element
}

// Const reference (read-only, efficient for large objects)
void printLargeObject(const vector<int>& vec) {
    // vec cannot be modified here
    for(int num : vec) {
        cout << num << " ";
    }
}

int main() {
    int x = 5, y = 10;
    
    swapByValue(x, y);
    cout << "x=" << x << ", y=" << y << endl;  // Still 5, 10
    
    swapByReference(x, y);
    cout << "x=" << x << ", y=" << y << endl;  // 10, 5
    
    swapByPointer(&x, &y);
    cout << "x=" << x << ", y=" << y << endl;  // 5, 10
    
    // Modify array element via reference return
    int arr[] = {1, 2, 3, 4, 5};
    getElement(arr, 2) = 100;  // arr[2] = 100
    cout << arr[2] << endl;    // 100
    
    return 0;
}

References vs Pointers

cpp

// Comparison table:

// | Feature        | Reference               | Pointer                 |
// |----------------|-------------------------|-------------------------|
// | Declaration    | int& ref = var;         | int* ptr = &var;        |
// | Reassignment   | Cannot be reassigned    | Can be reassigned       |
// | Null value     | Cannot be null          | Can be null             |
// | Indirection    | Automatic (ref)         | Manual (*ptr)           |
// | Address-of     | &ref gives var's address| &ptr gives ptr's address|
// | Arithmetic     | Not allowed             | Allowed                 |
// | Memory         | No separate memory      | Has its own memory      |

// Examples:

int value = 42;

// Reference
int& ref = value;    // Must be initialized
// int& ref2;        // ERROR: must initialize
// ref = NULL;       // ERROR: cannot be null
// &ref is same as &value

// Pointer
int* ptr = &value;   // Can be initialized later
ptr = nullptr;       // Can be null
int* ptr2;           // OK (uninitialized, dangerous!)
ptr2 = &value;       // Reassignment allowed
ptr++;               // Pointer arithmetic allowed

// Function parameters
void funcRef(int& param) {
    param = 100;  // Direct modification
}

void funcPtr(int* param) {
    if(param) {   // Must check for null
        *param = 100;  // Dereference needed
    }
}

int main() {
    int x = 10;
    
    funcRef(x);   // Call with variable
    cout << x << endl;  // 100
    
    funcPtr(&x);  // Call with address
    cout << x << endl;  // 100
    
    // When to use each:
    
    // Use references when:
    // 1. Function needs to modify argument
    // 2. Avoid copying large objects
    // 3. Operator overloading
    // 4. Range-based for loops
    
    // Use pointers when:
    // 1. Need to handle optional/null values
    // 2. Need pointer arithmetic
    // 3. Dynamic memory allocation
    // 4. Working with C APIs
    // 5. Polymorphism with base class pointers
    
    return 0;
}

// Reference in range-based for loop
vector<int> numbers = {1, 2, 3, 4, 5};
for(int& num : numbers) {  // Reference avoids copy
    num *= 2;  // Modify original elements
}

// Pointer for polymorphism
class Base { virtual void show() {} };
class Derived : public Base {};

Base* bptr = new Derived();  // Base class pointer to derived object
// Use dynamic_cast for safe downcasting

Reference to Pointer and Pointer to Reference

cpp

// Reference to pointer
int x = 10;
int y = 20;
int* ptr = &x;

int*& refToPtr = ptr;  // Reference to a pointer
refToPtr = &y;         // Now ptr points to y

cout << *ptr << endl;  // 20

// Pointer to reference is NOT allowed
// int&* ptrToRef;     // ERROR: pointer to reference is illegal

// Pointer to pointer (double pointer)
int value = 42;
int* ptr1 = &value;
int** ptr2 = &ptr1;    // Pointer to pointer

cout << **ptr2 << endl;  // 42 (dereference twice)

// Use case: Modify pointer in function
void allocateMemory(int** ptr) {
    *ptr = new int(100);  // Modify the original pointer
}

int main() {
    int* myPtr = nullptr;
    allocateMemory(&myPtr);
    cout << *myPtr << endl;  // 100
    delete myPtr;
    
    return 0;
}

Best Practices Summary

cpp

// 1. Prefer references over pointers when:
//    - No null value needed
//    - No reassignment needed
//    - Working within current scope

// 2. Use pointers when:
//    - Dealing with dynamic memory
//    - Need optional/null values
//    - Working with C interfaces
//    - Implementing data structures

// 3. Use const references for:
//    - Large object parameters
//    - Read-only access

// 4. Avoid raw pointers for ownership:
//    - Use smart pointers (unique_ptr, shared_ptr) instead

// 5. Always initialize pointers:
//    - Either to valid address or nullptr

// 6. Check for null before dereferencing

// 7. Use references in range-based for loops

// 8. Be careful with reference returns:
//    - Never return reference to local variable

// Example of good practices:
#include <memory>
#include <vector>

void processData(const std::vector<int>& data) {  // Const reference
    for(const int& num : data) {                  // Reference in loop
        // Process without copying
    }
}

std::unique_ptr<int[]> createArray(int size) {    // Smart pointer
    return std::make_unique<int[]>(size);         // Automatic cleanup
}

int& getFromArray(std::vector<int>& arr, int index) {
    if(index >= 0 && index < arr.size()) {
        return arr[index];  // OK: returns reference to existing element
    }
    throw std::out_of_range("Invalid index");
}

// BAD: Returning reference to local
int& badFunction() {
    int local = 42;
    return local;  // DANGER: local destroyed after function returns
}

Complete Example: String Manipulation Program

cpp

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <memory>

using namespace std;

// Function using C-style strings
void processCString(const char* str) {
    char buffer[100];
    strcpy(buffer, str);
    cout << "C-string length: " << strlen(buffer) << endl;
    cout << "Uppercase: ";
    
    for(int i = 0; buffer[i] != '\0'; i++) {
        buffer[i] = toupper(buffer[i]);
        cout << buffer[i];
    }
    cout << endl;
}

// Function using std::string
void processStdString(const string& str) {
    string upper = str;
    for(char& c : upper) {
        c = toupper(c);
    }
    
    cout << "std::string length: " << str.length() << endl;
    cout << "Uppercase: " << upper << endl;
    
    // Find vowels using pointer-like iterators
    cout << "Vowels at positions: ";
    for(auto it = str.begin(); it != str.end(); ++it) {
        char c = tolower(*it);
        if(c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
            cout << (it - str.begin()) << " ";
        }
    }
    cout << endl;
}

// Function demonstrating pointers and references
void modifyValues(int* ptr, int& ref) {
    if(ptr) {
        *ptr *= 2;  // Modify through pointer
    }
    ref += 10;      // Modify through reference
}

int main() {
    // C-style string
    char cstr[] = "Hello World";
    processCString(cstr);
    
    // std::string
    string str = "Programming in C++";
    processStdString(str);
    
    // Pointers and references
    int a = 5, b = 10;
    int* ptr = &a;
    int& ref = b;
    
    cout << "\nBefore: a=" << a << ", b=" << b << endl;
    modifyValues(ptr, ref);
    cout << "After: a=" << a << ", b=" << b << endl;
    
    // Dynamic array with pointer
    int size = 5;
    unique_ptr<int[]> arr(new int[size]);  // Smart pointer
    
    // Fill array using pointer arithmetic
    for(int i = 0; i < size; i++) {
        arr[i] = i * 10;
    }
    
    // Access using pointer
    int* p = arr.get();
    cout << "\nArray elements: ";
    for(int i = 0; i < size; i++) {
        cout << *(p + i) << " ";  // Pointer arithmetic
    }
    cout << endl;
    
    // No need to delete - smart pointer handles it
    
    return 0;
}

This comprehensive guide covers arrays, strings, pointers, and references in C++ with practical examples. Understanding these concepts is crucial for effective C++ programming and memory management.

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?