C++ Functions: Parameters, Return Values, Overloading,
이 글의 핵심
Functions are the building blocks of C++ programs. This guide covers everything beginners need: how to define and call functions, when to pass by value vs reference, how overloading works, and the pitfalls to avoid.
Why Functions?
Functions give a name to a block of code so you can reuse it without copying. They break large programs into smaller, testable pieces.
// Without functions — repeated code
double area1 = 3.14159 * 5.0 * 5.0;
double area2 = 3.14159 * 3.0 * 3.0;
// With a function — write once, use anywhere
double circleArea(double radius) {
return 3.14159 * radius * radius;
}
double area1 = circleArea(5.0);
double area2 = circleArea(3.0);
Function Anatomy
// Return type Name Parameters
double add (double a, double b) {
return a + b; // body
}
Every part matters:
- Return type: what type the function produces (
voidif nothing) - Name: what you call it
- Parameters: inputs (can have zero or many)
- Body: the code that runs
return: sends a value back to the caller
Declaration vs Definition
A declaration tells the compiler a function exists (its name, return type, parameter types). A definition provides the actual code. You can declare a function before defining it:
// Declaration (prototype) — put in header files or at top of file
double squareRoot(double x);
void printLine(const std::string& text);
// Use the function before the definition
int main() {
std::cout << squareRoot(16.0) << '\n'; // 4.0
printLine("Hello");
}
// Definition — the actual implementation
double squareRoot(double x) {
return std::sqrt(x);
}
void printLine(const std::string& text) {
std::cout << text << '\n';
}
In larger projects, declarations go in .h header files and definitions go in .cpp source files.
Parameters: Value, Reference, and Pointer
Pass by Value
A copy of the argument is made. Changes inside the function don’t affect the caller:
void doubleIt(int x) {
x *= 2; // modifies the copy, not the caller's variable
}
int main() {
int n = 5;
doubleIt(n);
std::cout << n; // still 5
}
Use when: the type is small (int, double, char, small structs), or you intentionally want a local copy to modify.
Pass by Reference
An alias to the caller’s variable — no copy, changes affect the caller:
void doubleInPlace(int& x) { // & means reference
x *= 2; // modifies the caller's variable
}
int main() {
int n = 5;
doubleInPlace(n);
std::cout << n; // 10
}
Use when: you need to modify the caller’s variable (output parameter).
Pass by const Reference
Efficient read-only access — no copy, but cannot be modified:
double sumVector(const std::vector<double>& v) { // const & — no copy, no modification
double total = 0;
for (double x : v) total += x;
return total;
}
Use when: the type is large (string, vector, any struct) and the function only reads it. This is the most common pattern for large types in C++.
Pass by Pointer
Similar to reference, but allows nullptr (no argument):
void process(const std::string* text) {
if (text == nullptr) {
std::cout << "(nothing)\n";
return;
}
std::cout << *text << '\n';
}
int main() {
std::string s = "hello";
process(&s); // pass address
process(nullptr); // no argument
}
Use when: null is a valid state (optional parameter). Prefer std::optional<T> in modern C++.
Quick Reference
| Type | Syntax | Copy? | Modifiable? | Use for |
|---|---|---|---|---|
| Value | int x | Yes | Local only | Small types |
| Const ref | const T& x | No | No | Large read-only types |
| Ref | T& x | No | Yes | Output parameters |
| Pointer | T* x | No | Yes | Optional parameters |
Return Values
Returning a Value
int add(int a, int b) {
return a + b;
}
std::string greet(const std::string& name) {
return "Hello, " + name + "!";
}
Every non-void function must return a value on all code paths. Modern compilers warn or error when a path exits without returning.
Returning Large Objects (RVO)
You can return large objects by value — the compiler eliminates the copy:
std::vector<int> makeRange(int start, int end) {
std::vector<int> result;
for (int i = start; i < end; i++) {
result.push_back(i);
}
return result; // RVO: constructed directly in caller's memory — no copy
}
int main() {
auto v = makeRange(0, 1000); // efficient — no extra copy
}
Never Return References to Locals
A local variable is destroyed when the function returns. Returning a reference to it is undefined behavior:
// WRONG — dangling reference
int& getLocal() {
int x = 42;
return x; // x is destroyed here — reference is dangling
}
// CORRECT — return by value
int getLocal() {
int x = 42;
return x; // copy returned, x destroyed — caller gets the copy
}
void Functions
Functions that perform actions but produce no value use void:
void printDivider(char ch, int count) {
for (int i = 0; i < count; i++) {
std::cout << ch;
}
std::cout << '\n';
}
// void functions use return; with no value to exit early
void processIfValid(int value) {
if (value < 0) return; // early exit
// ...process...
}
Default Arguments
Parameters can have default values when not provided:
void printBox(int width, int height = 5, char fill = '*') {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
std::cout << fill;
}
std::cout << '\n';
}
}
int main() {
printBox(10); // width=10, height=5, fill='*'
printBox(8, 3); // width=8, height=3, fill='*'
printBox(6, 4, '#'); // width=6, height=4, fill='#'
}
Rules:
- Defaults apply right-to-left — all parameters to the right of a default must also have defaults
- Put defaults in the declaration (header), not in the definition
// Header — declaration with defaults
void connect(const std::string& host, int port = 8080, bool secure = false);
// Source — definition without defaults (they're already in the header)
void connect(const std::string& host, int port, bool secure) {
// ...
}
Function Overloading
Multiple functions with the same name but different parameter types:
// Three versions of print — different parameter types
void print(int value) {
std::cout << "int: " << value << '\n';
}
void print(double value) {
std::cout << "double: " << value << '\n';
}
void print(const std::string& value) {
std::cout << "string: " << value << '\n';
}
int main() {
print(42); // calls print(int)
print(3.14); // calls print(double)
print("hello"); // calls print(const string&)
}
You cannot overload on return type alone — the parameter list must differ:
int getValue(); // OK
double getValue(); // compile error — same name and parameters
Recursion
A function that calls itself. Classic examples:
// Factorial: n! = n * (n-1) * ... * 1
long long factorial(int n) {
if (n <= 1) return 1; // base case
return n * factorial(n - 1); // recursive case
}
// Fibonacci — note: O(2^n) time, impractical for large n
int fib(int n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
// Better: iterative Fibonacci — O(n) time
long long fibIterative(int n) {
if (n <= 1) return n;
long long a = 0, b = 1;
for (int i = 2; i <= n; i++) {
long long c = a + b;
a = b;
b = c;
}
return b;
}
Every recursive function needs a base case that stops the recursion. Without it, the program runs until the stack overflows.
Common Mistakes
Calling before declaring:
int main() {
result = add(2, 3); // error: add not declared yet
}
int add(int a, int b) { return a + b; }
// Fix: declare add before main, or define add before main
Missing return on some path:
int sign(int x) {
if (x > 0) return 1;
if (x < 0) return -1;
// compiler may warn: control reaches end without return
// Fix: add return 0;
}
Passing large types by value:
double sumAll(std::vector<int> v) { ... } // copies the entire vector
double sumAll(const std::vector<int>& v) { ... } // no copy — correct
Returning reference to local:
const std::string& getName() {
std::string name = "Alice"; // local variable
return name; // UB: name destroyed at end of function
}
Practical Example: String Utilities
#include <string>
#include <algorithm>
#include <sstream>
#include <vector>
// Count occurrences of a character
int countChar(const std::string& s, char target) {
int count = 0;
for (char c : s) {
if (c == target) count++;
}
return count;
}
// Check if string is a palindrome
bool isPalindrome(const std::string& s) {
std::string lower = s;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
std::string reversed = lower;
std::reverse(reversed.begin(), reversed.end());
return lower == reversed;
}
// Split string by delimiter
std::vector<std::string> split(const std::string& s, char delimiter) {
std::vector<std::string> result;
std::stringstream ss(s);
std::string token;
while (std::getline(ss, token, delimiter)) {
result.push_back(token);
}
return result;
}
int main() {
std::cout << countChar("mississippi", 's') << '\n'; // 4
std::cout << isPalindrome("racecar") << '\n'; // 1 (true)
std::cout << isPalindrome("hello") << '\n'; // 0 (false)
auto words = split("one,two,three", ',');
for (const auto& w : words) {
std::cout << w << '\n'; // one / two / three
}
}
Key Takeaways
- Pass small types by value, large types by const reference — this is the most common function parameter pattern
- Const reference (
const T&) gives efficient read-only access without copying - Return by value for most things — RVO eliminates the copy overhead
- Never return a reference to a local variable — it’s undefined behavior (dangling reference)
- Overloading lets you use the same name for functions that do the same thing with different types
- Default arguments go in the declaration (header), not the definition
- Recursion needs a base case — always think about when it stops
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. Complete C++ function guide for beginners: declaration vs definition, pass by value/reference/pointer, return rules.
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- C++ 조건문 | if/else/switch ‘완벽 정리’ [실수 방지 팁]
- C++ Classes and Objects: Constructors, Access Control, and
- C++ 반복문 | for/while/do-while ‘완벽 마스터’ [무한루프 탈출]
Keywords Covered in This Article (Related Search Terms)
This article covers C++, functions, parameters, return, beginner.