Chapter 4: Functions, References, and Pointers

In C++, functions serve as the architectural foundation of your program. While they follow the basic principles learned in C, C++ introduces two game-changing features: References and Pass-by-Reference. These allow you to manipulate data directly without the complexity and risks often associated with C-style pointers.

1. Pass-by-Value vs. Pass-by-Reference

By default, C++ passes arguments to functions by "value," meaning the function creates a local copy of the data. For small types like int, this is fine. However, for large objects like std::string or custom classes, copying data is slow and memory-intensive.

A Reference (denoted by &) allows a function to access the original variable without creating a copy. Any change made to the reference inside the function directly updates the original variable.

void increment(int &num) {
    num++; // Updates the original variable
}

2. Constant References

If you need to access a large object (like a complex class) but don't want the function to accidentally change it, use a const reference. This provides the speed of pass-by-reference with the safety of read-only access.

void display_data(const std::string &data) {
    std::cout << data << std::endl;
}

3. Pointers in C++

C++ retains C-style pointers, but they are used sparingly in modern C++. A pointer holds the memory address of another variable. While they offer extreme control, they are a common source of memory leaks and segmentation faults. Whenever possible, prefer using references, as they are safer and guaranteed to refer to a valid object.

4. Function Overloading

One feature C++ introduces that C lacks is Function Overloading. You can define multiple functions with the same name, provided they have different parameter types or counts. This makes your code more intuitive, as you can use the same function name for different data types.

void print(int i) { std::cout << "Integer: " << i << std::endl; }
void print(std::string s) { std::cout << "String: " << s << std::endl; }

Common Pitfalls

Try It Yourself

  1. Write a function that swaps two integers using references.
  2. Create an overloaded function named calculate that performs addition for both integers and floating-point numbers.
  3. Test a function that accepts a large string by const reference to observe the performance difference compared to pass-by-value.

Understanding Pointers

A pointer is a variable that stores the memory address of another variable, rather than a value itself. Pointers are one of C++'s most powerful — and initially confusing — features.

int age = 25;
int* agePtr = &age;   // agePtr stores the address of age
cout << *agePtr;       // dereferencing: prints 25

References vs Pointers

A reference is like an alias for an existing variable — it's simpler to use than a pointer because you don't need to dereference it, and it can't be null.

void increment(int &num) {
    num++;
}

int x = 5;
increment(x);
cout << x;  // 6