C++ Function Parameters
How a parameter is declared decides whether the function gets a copy, can change the caller's variable, or reads it without copying. Choosing well makes programs both correct and fast.
Three ways to pass
| Parameter | The function gets | Use it for |
|---|---|---|
int x | a copy | small values (numbers, characters) |
int& x | the caller's variable | values the function must change |
const std::string& s | the original, read-only | big values the function only reads |
#include <iostream>
#include <string>
void byValue(int n) { n = 100; }
void byReference(int& n) { n = 100; }
void show(const std::string& text) { std::cout << text << " (" << text.size() << ")\n"; }
int main() {
int a = 5, b = 5;
byValue(a);
byReference(b);
std::cout << "a = " << a << ", b = " << b << "\n";
show("passed without copying");
return 0;
}a = 5, b = 100 passed without copying (22)
Default arguments
A parameter can have a default value, used when the call leaves it out. Defaults must come at the end of the parameter list.
#include <iostream>
#include <string>
void greet(const std::string& name, const std::string& greeting = "Hello", int times = 1) {
for (int i = 0; i < times; i++) {
std::cout << greeting << ", " << name << "!\n";
}
}
int main() {
greet("Asha");
greet("Ravi", "Welcome");
greet("Kiran", "Hi", 2);
return 0;
}Hello, Asha! Welcome, Ravi! Hi, Kiran! Hi, Kiran!
Returning several values
A function returns one value, but that value can be a struct, or a std::pair for two results. Structured bindings (auto [a, b] = ...) unpack it neatly:
#include <iostream>
#include <utility>
#include <vector>
struct Stats {
int min, max;
double average;
};
Stats analyse(const std::vector<int>& v) {
Stats s{v[0], v[0], 0};
double sum = 0;
for (int x : v) {
if (x < s.min) s.min = x;
if (x > s.max) s.max = x;
sum += x;
}
s.average = sum / v.size();
return s;
}
std::pair<int, int> divide(int a, int b) {
return {a / b, a % b};
}
int main() {
auto [lo, hi, avg] = analyse({7, 2, 9, 4});
std::cout << lo << " " << hi << " " << avg << "\n";
auto [q, r] = divide(17, 5);
std::cout << "17 / 5 = " << q << " remainder " << r << "\n";
return 0;
}2 9 5.5 17 / 5 = 3 remainder 2
Returning a struct is usually clearer than output parameters (references the function fills in), because the call shows what comes back.
A simple rule
For parameters the function only reads: pass numbers, characters and bool by value, and everything bigger (std::string, std::vector, your own classes) **by const&. For parameters the function must change, pass by &**. Following this rule gives correct and fast code in nearly every case.
Practice exercises
- Write
void scale(std::vector<double>& v, double factor = 2.0)and call it with and without the factor. - Write a function that returns the number of vowels and consonants in a string as a
std::pair. - Pass a big vector by value and by
const&and explain which is better and why.