Skip to content
Laviyx Learn

Try

C++ course menu

C++ Function Parameters: Pass by Value, by Reference and by const Reference

Learn how C++ passes arguments to functions: pass by value (a copy), pass by reference to modify the caller's variable, pass by const reference to avoid copies, returning several values, and how to choose the right parameter type.

Beginner9 min readUpdated
On this page

How you write a parameter decides what the function receives: a copy of the argument, or a reference to the caller's own variable. Choosing correctly makes your functions both correct and fast.

Pass by value: the function gets a copy#

By default, parameters are copies. Changing a copy has no effect on the caller's variable:

C++
#include <iostream>

void add_bonus(int salary) {
    salary += 5000;
    std::cout << "Inside: " << salary << '\n';
}

int main() {
    int salary = 50000;
    add_bonus(salary);
    std::cout << "Outside: " << salary << '\n';
}
Output
Inside: 55000
Outside: 50000

Pass by value is simple and safe, and ideal for small types such as int, double, char and bool.

Pass by reference: change the caller's variable#

Adding & after the type makes the parameter a reference: another name for the caller's variable. Changes inside the function affect the original:

C++
#include <iostream>

void add_bonus(int& salary) {
    salary += 5000;
}

int main() {
    int salary = 50000;
    add_bonus(salary);
    std::cout << salary << '\n';
}
Output
55000

The classic example is swap, which cannot work with copies:

C++
#include <iostream>

void swap_values(int& a, int& b) {
    int temp = a;
    a = b;
    b = temp;
}

int main() {
    int x = 1;
    int y = 2;
    swap_values(x, y);
    std::cout << x << ' ' << y << '\n';
}
Output
2 1

A non-const reference parameter must be given a variable, not a literal: swap_values(1, 2) does not compile, because there is no variable to change.

Pass by const reference: no copy, no changes#

Copying a large object, such as a long std::string or a std::vector with a million elements, is slow. A const reference gives the function read-only access to the original, without copying:

C++
#include <iostream>
#include <vector>

double average(const std::vector<double>& values) {
    double sum = 0;
    for (double v : values) {
        sum += v;
    }
    return sum / values.size();
}

int main() {
    std::vector<double> temps = {31.5, 29.0, 33.5, 30.0};
    std::cout << average(temps) << '\n';
}
Output
31

If the function tried to change values, the compiler would stop it. Unlike a plain reference, a const reference also accepts temporary values, such as average({1, 2, 3}).

Which one should I use?#

You want to…Parameter typeExample
Read a small value (int, double, char, bool)by valueint n
Read a larger object (string, vector, class)by const referenceconst std::string& s
Change the caller's variableby referenceint& total
Take a copy you will modify or keep anywayby valuestd::string s

The first two rows cover most functions you will write.

Returning several values#

A function returns one value, but that value can hold several parts. Modern C++ prefers returning a struct or std::pair over "output" reference parameters, because the result is clear at the call site:

C++
#include <iostream>
#include <utility>
#include <vector>

std::pair<int, int> min_max(const std::vector<int>& values) {
    int lowest = values[0];
    int highest = values[0];
    for (int v : values) {
        if (v < lowest) lowest = v;
        if (v > highest) highest = v;
    }
    return {lowest, highest};
}

int main() {
    auto [low, high] = min_max({12, 7, 21, 9});
    std::cout << low << ' ' << high << '\n';
}
Output
7 21

auto [low, high] = ... is a structured binding (C++17) that unpacks the pair into two variables. You will see structs in Structs and Enums.

Arrays and C-style strings#

Older code passes arrays as a pointer plus a separate size, such as int sum(const int* data, int n). With std::vector, std::array and std::string, the container knows its own size, so pass it by const reference instead. You will learn about pointers in Pointers.

Common mistakes#

Practice#

Practice exercise

Write a function apply_discount(double& price, double percent) that reduces price by the given percentage. Apply 10% to a price of 850 and print the result.

Show solution
C++
#include <iostream>

void apply_discount(double& price, double percent) {
    price -= price * percent / 100;
}

int main() {
    double price = 850;
    apply_discount(price, 10);
    std::cout << price << '\n';
}
Output
765

price is a reference because the function changes it; percent is only read, and it is a small type, so it is passed by value.

Practice exercise

Write int count_vowels(const std::string& text) and print the number of vowels in "Programming in C++ is fun".

Show solution
C++
#include <cctype>
#include <iostream>
#include <string>

int count_vowels(const std::string& text) {
    int count = 0;
    for (char c : text) {
        char lower = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
        if (lower == 'a' || lower == 'e' || lower == 'i' || lower == 'o' || lower == 'u') {
            ++count;
        }
    }
    return count;
}

int main() {
    std::cout << count_vowels("Programming in C++ is fun") << '\n';
}
Output
6

std::tolower (from <cctype>) expects a value that fits in unsigned char, which is why the character is cast first.

Key takeaway#

Finished this lesson?