Function Declaration
A function in programming is generally a collection of several statements. We can also call it a "subroutine". In programming, if there are some repeated processes, we can extract them to form a function. A function can receive several values; these are called the function's parameters. A function can also return a value; this is called the function's return value.
To declare a function, we need its return-value type, its name, and its parameter list.
// Return-value type: int
// Function name: some_function
// Parameter list: int, int
int some_function(int, int);
As shown above, we declare a function named some_function. It needs to receive two parameters of type int, and its return-value type is also int. We can think of this function as performing some operation on the two integers passed to it and returning a result of the same type.
Implementing a Function: Writing the Function Definition
The function declaration (declaration) alone is not enough. It only allows us to know the function's interface type (that is, what data it receives and what data it returns) when calling it, but it lacks a specific internal implementation, namely the function's definition. We can write code to implement this function elsewhere after the declaration (it can also be implemented in another file, but the separately compiled files need to be provided together at link time).
If a function has a return value, it needs to return the value to the caller through a return statement. Once a function executes a return statement, it immediately ends the current function and no longer executes subsequent statements.
int some_function(int, int); // declaration
/* some other code here... */
int some_function(int x, int y) { // definition
int result = 2 * x + y;
return result;
result = 3; // this statement will not be executed
}
When defining a function, we give names to the variables in its parameter list. This allows us to use these variables in the function definition.
If it is in the same file, we can also combine the declaration and definition into one, in other words, complete the definition at the time of declaration.
int some_function(int x, int y) { return 2 * x + y; }
If a function does not need a return value, mark its return-value type as void. If a function does not need parameters, its parameter list can be left empty. Similarly, a function with no return value also ends execution when it reaches the return; statement.
void say_hello() {
cout << "hello!\n";
cout << "hello!\n";
cout << "hello!\n";
return;
cout << "hello!\n"; // this statement will not be executed
}
Function Calls
Like variables, a function must first be declared before it can be used. The act of using a function is called a "call". We can call other functions inside any function, including the function itself. The act of a function calling itself is called recursion.
In most languages, a function call is written as the function name followed by a pair of parentheses (), such as foo(). If a function requires parameters, we fill in the required parameters in order inside the parentheses, separated by commas, such as foo(1, 2). A function call is also an expression, and the return value of the function is the value of the expression.
The parameters written in a function declaration can be understood as variables that can be used inside the current call of the function; these variables are initialized with the values passed from the call site. Consider the following example:
void foo(int, int);
/* ... */
void foo(int x, int y) {
x = x * 2;
y = y + 3;
}
/* ... */
a = 1;
b = 1;
// Before the call: a = 1, b = 1
foo(a, b); // call foo
// After the call: a = 1, b = 1
In the example above, foo(a, b) is a call to foo. During the call, the variables x and y in foo are initialized with the values of a and b at the call site, respectively. Therefore, modifying the variables x and y in foo does not affect the values of the variables at the call site.
If we need to modify the values of variables in a function (subroutine), we need to use the "pass by reference" method.
void foo(int& x, int& y) {
x = x * 2;
y = y + 3;
}
/* ... */
a = 1;
b = 1;
// Before the call: a = 1, b = 1
foo(a, b); // call foo
// After the call: a = 2, b = 4
In the code above, we see that an & (ampersand) has been added after int in the function parameter list. This represents a reference to a value of type int. When calling foo, the variables a and b at the call site initialize the two references to int, x and y, in foo, respectively. x and y in foo can be understood as "aliases" of the variables a and b at the call site; that is, operations on x and y in foo are operations on a and b at the call site.
The main Function
In particular, every C/C++ program needs to have a function named main. Every program starts running from the main function.
The
mainfunction can also have parameters. Through the parameters of themainfunction, we can obtain instructions passed to the program from outside (that is, "command-line arguments") and respond differently.
Here is a piece of code that calls a function (subroutine):
// hello_subroutine.cpp
#include <iostream>
void say_hello() {
std::cout << "hello!\n";
std::cout << "hello!\n";
std::cout << "hello!\n";
}
int main() {
say_hello();
say_hello();
}