Calling Functions and Passing Arguments
C++ programs get their work done mainly by calling functions.
Why Programs Are Built From Called Functions
C++ programs get their work done mainly by calling functions. Most C++ programs are not one long list of instructions. Instead, the work is split into named pieces, and the program gets things done by calling those pieces at the right moments. Each piece is a function.
Keep that picture in mind as you read. A program is a set of named pieces that call one another. The rest of this article follows a single call from start to finish, so you can see exactly where the program goes and how it comes back.
What do you think happens?
main() reaches a line that calls add(2, 3). Before reading on, what do you think happens next?
Reveal answer
Execution jumps into add(), runs its body, and then returns to the line after the call.
A call transfers control to the function, the function does its operation, and control comes back to the place the call was made. The rest of this article explains the rules that make this work in C++.
Tracing One Call From main
Follow the path a single call takes. The calling code, here main(), pauses at the call. The function body performs its operation. A value then travels back to the place the call was made, where it can be used. The example below is written for this article to show that path in real code.
5- Line 3 is a declaration: it makes add known before main uses it
- Line 6 is the call: control moves into add with 2 and 3 supplied
- Line 6 finishes only after add hands back 5, which is stored in total
- Lines 11 to 13 are the definition: they specify how add does its operation
Read the trace in order. Execution reaches the call on the line that assigns total. It moves into add. The body computes a + b. Then the result comes back to the line where the call was made, and the assignment finishes. Execution then continues with the line after that, which prints the value.
Declaring Versus Defining a Function
A function cannot be called unless it has been previously declared. The declaration comes earlier in the program than the call. This is a rule the compiler relies on: when the code says to call a function, the function must already be known to the program. Declaring a function introduces its name and the shape it has, so that code written earlier can refer to it correctly.
Defining a function is a different job. A definition specifies how the function's operation is to be done. It contains the body, the block of statements that does the work. So the two ideas separate cleanly: a declaration makes the function known, and a definition says what the function actually does.
A useful way to keep these apart is to think of a declaration as an entry in a list of available tools, and the definition as the instructions for how each tool works. The list lets other code refer to the tool by name. The instructions are where the operation is actually specified. In the program above, line 3 is the list entry and lines 11 to 13 are the instructions.
Reading the Return Type in a Signature
Every function has a return type, and that type tells you whether the function gives a value back to the code that called it. The return type is the part of the function's shape that answers this question before you ever look inside the body. Reading it first lets you predict what the caller can do with the result of the call.
Read the signature from left to right. The first word is the return type, which tells you what kind of value, if any, the caller receives. The next word is the name the caller uses. The parentheses hold the parameter list, which describes the values the caller passes in when it makes the call. In the example, the call add(2, 3) supplies 2 and 3, which fill a and b.
Void Versus Value-Returning Functions
The question to ask of any function is simple: does its return type say void, or does it name a kind of value? If it says void, the caller receives nothing back from the call. If it names a value type, the function is designed to give a value back, and the caller can use that value.
| Feature | Return type void | Return type names a value (for example int) |
|---|---|---|
| Does the caller receive a value? | No, nothing comes back | Yes, a value of that type comes back |
| Can the caller use the result? | No result to use | Yes, it can be stored or used in an expression |
| What the signature tells you | The call is for its effect only | The call produces a value of the named type |
| Example from this article | A function that only prints | int add(int a, int b) |
Reading the return type tells you what the caller can do with the call.
The return type is the first clue you have about a function, so check it before reading the body. A caller that expects a value depends on the return type being a value type. The return type is the part of the signature that sets that expectation.
Common Mistakes With Declarations and Return Types
Common mistake Calling a function before it has been declared
What it looks likeint main() { int t = add(2, 3); return t; } appears above any declaration of addWhy it failsA function cannot be called unless it has been previously declared, and the compiler relies on this order.
Do this insteadPlace the declaration, or the definition, of add before the line that calls it.
Common mistake Treating the declaration as if it contains the body
What it looks likeWriting only int add(int a, int b); and expecting the call to produce a sum
Why it failsA declaration makes the name and shape known. The definition is where the operation is specified.
Do this insteadProvide a definition with a body that performs the operation.
Common mistake Letting the declaration and definition disagree
What it looks likeDeclaring int add(int a, int b); but defining it with a different return type or different parameters
Why it failsThe declaration describes the shape the rest of the code relies on, so the definition must match that shape.
Do this insteadCopy the signature exactly from the declaration into the definition.
Common mistake Assuming a function returns a value because it has a name that sounds like a result
What it looks likeCalling a function named printTotal and expecting its result to be stored
Why it failsOnly the return type says whether a value comes back. A void return type means the caller receives nothing.
Do this insteadRead the return type first. If it says void, do not try to use a value from the call.
Practice Reading Signatures
Given the signature void report(int score);, can a caller write int x = report(90); and use the result? Explain using the return type. Then say what the caller receives from the call.
Hints
- Look at the first word of the signature, which is the return type.
- The source says a return type of void means the function does not return a value.
A program calls int square(int n) before any declaration or definition of square appears in the file. Describe what is wrong, then write the declaration that fixes it and identify its return type and parameter list.
Hints
- Recall that a call requires an earlier declaration.
- A declaration needs the same name, return type, and parameter list as the definition.
Key Takeaways
- C++ programs get their work done mainly by calling functions, which are named pieces that the program invokes at the right moments.
- A function must be declared before it is called. A declaration introduces its name and shape, while a definition specifies how the operation is done.
- The return type shows whether a function hands a value back. A void return type means the caller receives nothing, while a value type means the caller can use the result.
- Most errors with functions come from calls before declarations, mismatched signatures, and misreading what the return type promises.