CS 126 – Principle of Programming II - Functions
C
Example:
#include <iostream>
using namespace std;
// Print grade for the score
void printGrade(double score){
if (score >= 90.0)
cout << "A" << endl;
else if (score >= 80.0)
cout << "B" << endl;
else if (score >= 70.0)
cOut << "C" << endl;
else if (score >= 60.0)
cout << "D" << endl;
else
cout << "F" << endl;
}
int main(){
cout << "Enter a score: ";
double score;
cin >> score;
cout << "The grade is ";
printGrade(score);
return 0;
}
In this example,
printGradeis a void function that prints a grade based on the given score.
Value-Returning Function
A value-returning function returns a value of a specific type.
Example:
#include <iostream>
using namespace std;
// Return the grade for the score
char getGrade(double score){
if (score >= 90.0)
return 'A';
else if (score >= 80.0)
return 'B';
else if (score >= 70.0)
return 'C';
else if (score >= 60.0)
return 'D';
else
return 'F';
}
int main(){
cout << "Enter a score: ";
double score;
cin >> score;
cout << "The grade is ";
cout << getGrade(score) << endl;
return 0;
}
In this example,
getGradereturns a character representing the grade.
Passing Arguments by Value
By default, arguments are passed by value to parameters when invoking a function.
Example:
void nPrint(char ch, int n) {
for (int i = 0; i < n; i++)
cout << ch;
}
nPrint('a', 3)prints 'a' three times.The actual char parameter 'a' is passed to the parameter
ch, and 3 is passed ton.nPrint(3, 'a')passes 3 tochand 'a' ton, demonstrating that the order matters.
Modularizing Code
Modularizing code makes it easy to maintain and debug and enables code reuse.
Example:
#include <iostream>
using namespace std;
// Return the gcd of two integers
int gcd(int n1, int n2) {
int gcd = 1; // Initial gcd is 1
int k = 2; // Possible gcd
while (k <= n1 && k <= n2){
if (n1 % k == 0 && n2 % k == 0)
gcd = k; // Update gcd
k++;
}
return gcd; // Return gcd
}
int main(){
// Prompt the user to enter two integers
cout << "Enter first integer: ";
int n1;
cin >> n1;
cout << "Enter second integer: ";
int n2;
cin >> n2;
cout << "The greatest common divisor for " << n1 << " and " << n2 << " is " << gcd(n1, n2) << endl;
return 0;
}
This code calculates the greatest common divisor (GCD) of two integers using a separate function
gcd.
Overloading Functions
Overloading functions enables you to define functions with the same name as long as their signatures are different (different parameter types or number of parameters).
Examples:
#include <iostream>
using namespace std;
// Return the max between two int values
int max(int num1, int num2){
if (num1 > num2)
return num1;
else
return num2;
}
// Find the max between two double values
double max(double num1, double num2){
if (num1 > num2)
return num1;
else
return num2;
}
// Return the max among three double values
double max(double num1, double num2, double num3){
return max(max(num1, num2), num3);
}
int main() {
// Invoke the max function with int parameters
cout << "The maximum between 3 and 4 is " << max(3, 4) << endl;
// Invoke the max function with the double parameters
cout << "The maximum between 3.0 and 5.4 is " << max(3.0, 5.4) << endl;
// Invoke the max function with three double parameters
cout << "The maximum between 3.0, 5.4, and 10.14 is " << max(3.0, 5.4, 10.14) << endl;
return 0;
}
Function Prototypes
A function prototype declares a function without having to implement it.
It specifies the function's name, return type, and parameters.
Example:
#include <iostream>
using namespace std;
// Function prototype
int max(int num1, int num2);
double max(double num1, double num2);
double max(double num1, double num2, double num3);
int main() {
// Invoke the max function with int parameters
cout << "The maximum between 3 and 4 is " << max(3, 4) << endl;
// Invoke the max function with the double parameters
cout << "The maximum between 3.0 and 5.4 is " << max(3.0, 5.4) << endl;
// Invoke the max function with three double parameters
cout << "The maximum between 3.0, 5.4, and 10.14 is " << max(3.0, 5.4, 10.14) << endl;
return 0;
}
// Return the max between two int values
int max(int num1, int num2){
if (num1 > num2)
return num1;
else
return num2;
}
// Find the max between two double values
double max(double num1, double num2){
if (num1 > num2)
return num1;
else
return num2;
}
// Return the max among three double values
double max(double num1, double num2, double num3){
return max(max(num1, num2), num3);
}
Default Arguments
You can define default values for parameters in a function.
If an argument is not provided when the function is called, the default value is used.
#include <iostream>
using namespace std;
// Display area of a circle
void printArea(double radius = 1) {
double area = radius * radius * 3.14159;
cout << "area is " << area << endl;
}
int main() {
printArea(); // Uses default radius of 1
printArea(4); // Uses radius of 4
return 0;
}
In the above example, if
printArea()is called without any arguments, radius defaults to 1.
Inline Functions
C++ provides inline functions for improving performance, especially for short functions.
The compiler may replace the function call with the actual code of the function, reducing overhead.
#include <iostream>
using namespace std;
inline void f(int month, int year) {
cout << "month is " << month << endl;
cout << "year is " << year << endl;
}
int main() {
int month = 10, year = 2008;
f(month, year); // Invoke inline function
f(9, 2010); // Invoke inline function
return 0;
}
Local, Global, and Static Local Variables
A variable can be declared as local, global, or static local.
Local variables: Declared inside a function or a block.
Global variables: Declared outside all functions.
Static local variables: Declared inside a function but retain their values between function calls.
The Scope of Variables in a for Loop
A variable declared in the initialization part of a
forloop header has its scope in the entire loop.A variable declared inside a
forloop body has its scope limited to the loop body from its declaration to the end of the block.It's best to avoid redeclaring variables in nested blocks, as it can lead to confusion.
Static Local Variables
After a function completes its execution, all its local variables are destroyed (also known as automatic variables).
Static local variables retain their values between function calls. They are permanently allocated in memory for the lifetime of the program.
#include <iostream>
using namespace std;
void t1(); // Function prototype
int main(){
t1();
t1();
return 0;
}
void t1(){
static int x = 1;
int y = 1;
x++;
y++;
cout << "x is " << x << endl;
cout << "y is " << y << endl;
}
In the above example,
xis a static local variable, so its value is retained between calls tot1().yis a regular local variable, so it is reinitialized each timet1()is called.
Passing Arguments by Reference
Parameters can be passed by reference, making the formal parameter an alias of the actual argument.
Changes made to the parameters inside the function also affect the original arguments.
Example: Passing by Value (Does Not Work for Swapping)
#include <iostream>
using namespace std;
// Attempt to swap two variables - does not work!
void swap(int n1, int n2) {
cout << "\tInside the swap function" << endl;
cout << "\tBefore swapping n1 is " << n1 << " n2 is " << n2 << endl;
// Swap n1 with n2
int temp = n1;
n1 = n2;
n2 = temp;
cout << "\tAfter swapping n1 is " << n1 << " n2 is " << n2 << endl;
}
int main() {
// Declare and initialize variables
int num1 = 1;
int num2 = 2;
cout << "Before invoking the swap function, num1 is " << num1 << " and num2 is " << num2 << endl;
// Invoke the swap function to attempt to swap two variables
swap(num1, num2);
cout << "After invoking the swap function, num1 is " << num1 << " and num2 is " << num2 << endl;
return 0;
}
In this example,
num1andnum2are not swapped because changes ton1andn2do not affectnum1andnum2.
Example: Passing by Reference (Works for Swapping)
#include <iostream>
using namespace std;
// Swap two variables
void swap(int& n1, int& n2) {
cout << "\tInside the swap function" << endl;
cout << "\tBefore swapping n1 is " << n1 << " n2 is " << n2 << endl;
// Swap n1 with n2
int temp = n1;
n1 = n2;
n2 = temp;
cout << "\tAfter swapping n1 is " << n1 << " n2 is " << n2 << endl;
}
int main() {
// Declare and initialize variables
int num1 = 1;
int num2 = 2;
cout << "Before invoking the swap function, num1 is " << num1 << " and num2 is " << num2 << endl;
// Invoke the swap function to attempt to swap two variables
swap(num1, num2);
cout << "After invoking the swap function, num1 is " << num1 << " and num2 is " << num2 << endl;
return 0;
}
In this example,
n1andn2are references tonum1andnum2, so swappingn1andn2also swapsnum1andnum2.
Constant Reference Parameters
You can specify a constant reference parameter to prevent its value from being changed by accident.
// Return the max between two numbers
int max(const int& num1, const int& num2) {
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
Using
const int&ensures that the function cannot modify the original values ofnum1andnum2.