Week 5: Building Reusable Code with Functions
Learn to define and use functions to organize your C++ code effectively.
Explore Chapter 5Chapter 5: Functions - Modularizing Your Code
Defining Functions.
Functions are blocks of code designed to perform a specific task. They allow you to break down large programs into smaller, manageable, and reusable units. Using functions makes your code more organized, easier to understand, and simpler to debug and maintain.
Syntax
return_type function_name(parameter_type1 parameter_name1, parameter_type2 parameter_name2, ...) {
// Code block (function body)
statement1;
statement2;
// ...
return value; // Optional: returns a value of 'return_type'
}
- `return_type`: The data type of the value the function will return (e.g., `int`, `double`, `void` if it returns nothing).
- `function_name`: A descriptive name for the function (following identifier rules).
- `parameter list`: Enclosed in parentheses `()`, specifies the type and name of input values the function accepts. Can be empty if the function takes no input.
- `{ ... }`: Curly braces enclose the function body, containing the code to be executed.
- `return value;`: Sends a value back to the part of the code that called the function. The type of `value` must match `return_type`. Functions with `void` return type don't need a `return` statement, or can use `return;` to exit early.
Example: A Simple Greeting Function
#include <iostream>
#include <string>
// Function definition
void greet(std::string name) {
std::cout << "Hello, " << name << "!" << std::endl;
}
int main() {
greet("Alice"); // Calling the function
greet("Bob"); // Calling it again
return 0;
}
Function Prototypes (Declarations).
In C++, a function must be declared before it is called. If you define a function *after* the `main` function (or any function that calls it), you need to provide a function prototype (or declaration) beforehand.
A prototype tells the compiler the function's name, return type, and parameter types, without providing the function body.
Syntax
return_type function_name(parameter_type1, parameter_type2, ...); // Note the semicolon!
Parameter names are optional in the prototype but required in the definition.
Example
#include <iostream>
// Function prototype (declaration)
int add(int a, int b);
int main() {
int result = add(5, 3); // Function can be called because it was declared
std::cout << "Sum: " << result << std::endl; // Output: Sum: 8
return 0;
}
// Function definition (provided later)
int add(int a, int b) {
return a + b;
}
Prototypes are often placed in header files (`.h` or `.hpp`) for better organization in larger projects.
Parameters and Arguments (Pass by Value).
Parameters are the variables listed in the function definition. Arguments are the actual values passed to the function when it is called.
Pass by Value
By default, C++ passes arguments by value. This means a copy of the argument's value is made and passed to the function parameter. Any modifications made to the parameter inside the function do not affect the original argument outside the function.
#include <iostream>
void tryToModify(int num) {
num = 100; // Modifies the local copy (parameter 'num')
std::cout << "Inside function, num = " << num << std::endl; // Outputs 100
}
int main() {
int originalValue = 10;
tryToModify(originalValue);
std::cout << "Outside function, originalValue = " << originalValue << std::endl; // Outputs 10
return 0;
}
We will cover other ways of passing arguments (like pass by reference and pass by pointer) in Week 7, which allow functions to modify the original arguments.
Default Arguments
You can provide default values for parameters in the function declaration (or definition if no separate declaration exists). If the caller omits an argument for that parameter, the default value is used. Default arguments must come after non-default arguments in the parameter list.
#include <iostream>
void showValues(int a, int b = 10, int c = 20) {
std::cout << "a=" << a << ", b=" << b << ", c=" << c << std::endl;
}
int main() {
showValues(1); // Output: a=1, b=10, c=20
showValues(1, 55); // Output: a=1, b=55, c=20
showValues(1, 55, 99); // Output: a=1, b=55, c=99
return 0;
}
Returning Values (`return` Statement).
The `return` statement allows a function to send a value back to the caller. The type of the returned value must match the function's declared `return_type`.
#include <iostream>
double calculateArea(double radius) {
const double PI = 3.14159;
if (radius < 0) {
std::cout << "Error: Radius cannot be negative." << std::endl;
return 0.0; // Return a default value on error
}
double area = PI * radius * radius;
return area; // Return the calculated area
}
int main() {
double circleArea = calculateArea(5.0);
std::cout << "Area of circle: " << circleArea << std::endl;
return 0;
}
A function with a `void` return type doesn't return a value. It can use `return;` without a value to exit early.
Function Overloading.
C++ allows you to define multiple functions with the same name but with different parameter lists (differing in the number or type of parameters). This is called function overloading.
The compiler determines which version of the function to call based on the arguments provided during the function call.
#include <iostream>
#include <string>
// Overloaded functions named 'printData'
void printData(int data) {
std::cout << "Integer data: " << data << std::endl;
}
void printData(double data) {
std::cout << "Double data: " << data << std::endl;
}
void printData(std::string data) {
std::cout << "String data: " << data << std::endl;
}
int main() {
printData(100); // Calls the int version
printData(3.14); // Calls the double version
printData("C++"); // Calls the string version
return 0;
}
Note: Function overloading is based only on the parameter list, not the return type.
Variable Scope (Local vs. Global).
The scope of a variable determines where in the code it can be accessed.
Local Variables
Variables declared inside a function (or any block defined by `{}`) are local variables. They exist only within that function/block and cannot be accessed from outside.
void myFunction() {
int localVar = 50; // localVar is local to myFunction
std::cout << localVar; // OK here
}
int main() {
myFunction();
// std::cout << localVar; // Error! localVar is not in scope here
return 0;
}
Global Variables
Variables declared outside of any function have global scope. They can be accessed (and potentially modified) from any function within the same file (or across files if declared correctly using `extern`, which is more advanced).
#include <iostream>
int globalVar = 100; // Global variable
void printGlobal() {
std::cout << "Global variable: " << globalVar << std::endl; // Access global
}
void modifyLocal() {
int globalVar = 5; // This declares a *new local* variable hiding the global one
std::cout << "Local variable shadowing global: " << globalVar << std::endl;
}
int main() {
printGlobal(); // Accesses the global 100
modifyLocal(); // Accesses the local 5
printGlobal(); // Still accesses the global 100
return 0;
}
While global variables are accessible everywhere, excessive use is discouraged as it can make code harder to understand and maintain due to potential side effects from different functions modifying the same global state.