05 Functions

Learn how to design, call, and organize C++ functions, including parameters, return values, scope, overloading, and recursion.

and

A function is a named block of C++ statements that performs a specific task. Breaking a program into functions makes its parts easier to reuse, test, and understand.

A tells the compiler a function's name, return type, and types, but it does not contain the body. For example, int add(int first, int second); introduces a function that returns an integer and accepts two integer parameters.

A provides the implementation. The declaration and definition must agree about the function name, return type, and types. A declaration can appear before a definition, so main can call a function whose implementation appears later.

The general structure is a return type, a function name, a list, and a body. A function with return type void performs an action without returning a value. It may use return; to leave the function early, but it cannot return a value.

Takeaway: A declaration announces what a function looks like; a definition explains how it works.

Parameters, arguments, and return values

A is the variable named in a function's declaration or definition. An is the actual value supplied by a call. For a multiplication function with parameters named x and y, a call such as multiply(4, 6) supplies two arguments.

By default, C++ passes parameters by value. The function receives copies, so changing a does not change the caller's original variable. A reference , written with &, can allow the function to modify that original variable. A const reference can avoid a copy while preventing modification.

The is the result sent from a function to its caller. A function returning a non-void type should provide a compatible value along every possible execution path. A returned value can be stored, printed, or used as part of another function call.

Function calls transfer execution to the called function. Its parameters are initialized, its body runs, and control then returns to the statement after the call. Calls may be nested: the inner call finishes first, and its result becomes an for the outer call.

Returning a local variable by value is safe because the value is copied or moved to the caller. Returning a pointer or reference to a local variable is invalid because that local object no longer exists after the function ends.

Takeaway: Parameters receive information, arguments provide it, and a communicates a result back to the caller.

and local variables

The of a name is the part of the program where that name can be used. A variable declared inside a function or block is usually a local variable. Its begins at its declaration and ends at the end of its enclosing block.

Function parameters are available throughout the function body. A variable declared inside an inner block is unavailable after that block ends. An inner declaration can also hide a name from an outer ; this is called shadowing. Although shadowing is legal, descriptive and distinct names generally make programs clearer.

Ordinary local variables are independent between function calls. If a function creates a local counter, increments it, and prints it, each call normally starts with a new counter. A local variable declared static has a longer lifetime and retains its value between calls, so it should be used deliberately.

Example: A variable named value inside one function is separate from a variable with the same name in another function. The two functions cannot use each other's local variables directly; they must communicate through parameters, return values, or other deliberately shared mechanisms.

Takeaway: controls where names are visible, while lifetime controls how long the associated objects exist.

allows several functions in the same to share a name when their lists differ. The compiler chooses an overload by comparing the number and types of the supplied arguments, including applicable standard conversions.

For example, one area function might accept an integer side length, while another area function accepts a floating-point radius. A call with an integer selects the first overload, whereas a call with a floating-point selects the second when the choice is unambiguous.

Overloads may differ in the number of parameters, the types, or the order of types. They cannot differ only by return type. Therefore, declarations such as int getValue(); and double getValue(); do not form valid overloads. If multiple overloads are equally suitable, the call is ambiguous and the program is ill-formed.

Takeaway: Overloading gives one descriptive name several -based interfaces; the return type alone never selects an overload.

and the call stack

occurs when a function calls itself. A sound recursive design has a that stops the process and a recursive case that handles a smaller or simpler problem.

For a factorial function, the mathematical definition is:

0!=1,n!=n×(n−1)! for n>00! = 1, \qquad n! = n \times (n - 1)! \text{ for } n > 0

The returns one when the input is zero or one. The recursive case returns the input multiplied by a call using an input smaller by one. For an input of four, the calls eventually reach the and produce:

4!=4×3×2×1=244! = 4 \times 3 \times 2 \times 1 = 24

Each active call has its own parameters and local variables. These active calls are kept in the call stack. If never reaches its , calls continue until the program exhausts available stack space.

is natural for trees, nested structures, and divide-and-conquer algorithms. For other problems, a loop may be more efficient or easier to control. The complete recursive example can be organized so that main calls a power function, the power function recursively computes the result, and a separate printing function displays it.

Takeaway: Every recursive function needs progress toward a , and each call must reduce the remaining problem in a well-defined way.