0% found this document useful (0 votes)
8 views

Chapter - 1 Cp2 (Notion)

Chapter 1 discusses modular programming, which involves breaking a program into smaller, independent modules for easier development and maintenance. It covers the definition and purpose of functions in C++, including how to declare, define, and call them, as well as the importance of function prototypes. The chapter also explains variable scope, distinguishing between local and global variables, emphasizing the significance of local variables in preventing name conflicts.

Uploaded by

Elias
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views

Chapter - 1 Cp2 (Notion)

Chapter 1 discusses modular programming, which involves breaking a program into smaller, independent modules for easier development and maintenance. It covers the definition and purpose of functions in C++, including how to declare, define, and call them, as well as the importance of function prototypes. The chapter also explains variable scope, distinguishing between local and global variables, emphasizing the significance of local variables in preventing name conflicts.

Uploaded by

Elias
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 43

👨🏽‍💻

Chapter - 1 | Modular
Programming

Modular Programming and Modules:


1. Definition: Modular programming means breaking a program into smaller,
independent parts called modules.

2. Purpose: This approach helps in the effective development and maintenance


of large programs and projects.

3. Independent Modules: Each module can be programmed and tested


separately.

4. Grouping: Procedures with similar functionality are grouped together in the


same module.

5. Structure: A program is no longer a single large block; instead, it is divided


into smaller parts (modules) that work together to form the complete program.

This structure makes programs easier to understand, manage, and update.

1.1. Definition of Functions :


1. Modules as Functions: In C++, modules are implemented as functions.

2. Definition of a Function: A function is a subprogram that:

Acts on data.

May return a value.

Chapter - 1 | Modular Programming 1


3. Main Function: Every C++ program must have a main() function, which is
automatically called when the program starts.

The main() function can call other functions.

Those functions may call additional functions, creating a chain of calls.

4. Execution Flow:

When a function is called, the program’s execution switches to the body of


that function.

After the function completes, execution resumes on the next line after the
function call.

5. Design of Functions:

Functions should perform specific and easily understood tasks.

Complicated tasks should be broken into multiple smaller functions.

6. Types of Functions:

User-defined functions: Created by the programmer.

Built-in functions: Provided by the compiler package and ready to use.

7. Focus of Chapter: This chapter emphasizes user-defined functions.

1.1.1. Declaring and Defining Functions:


1. Two Steps to Use Functions:

Declaration: Introduces the function to the compiler by specifying its


name, return type, and parameters.

Definition: Explains how the function works (its implementation).

2. Function Prototype:

The declaration of a function is called its prototype.

3. Calling Functions:

Chapter - 1 | Modular Programming 2


A function cannot be called from another function unless it has been
declared first.

This ensures the compiler knows the function details before it is used in the
program.

1.1.1.1. Declaring a Function:


1. Ways to Declare a Function:

Write the prototype in a separate file and include it using the #include

directive.

Write the prototype in the same file where the function is used.

Define the function before any other function calls it, where the definition
itself acts as the declaration.

2. Why Function Prototypes Are Better:

Avoids requiring functions to appear in a specific order in a file, which


improves maintainability.

Resolves mutual dependencies between functions (e.g., Function A calls


Function B and vice versa).

Helps detect mismatches in parameters or return types during compilation,


aiding in debugging.

3. Function Prototypes:

Prototypes for built-in functions are included in library files (e.g., via
#include ).

For user-defined functions, you must explicitly include the prototype.

Syntax:

return_type function_name(type parameter1, type paramet


er2, ...);

Chapter - 1 | Modular Programming 3


The prototype must match the definition exactly in return type, function
name, and parameter types.

4. Naming Parameters:

Naming parameters in the prototype is optional but improves clarity.

Example:

long Area(int length, int width); // Clearer prototype


long Area(int, int); // Legal but less clea
r

5. Examples of Prototypes:

long FindArea(long length, long width); (returns a long , takes two


parameters).

void PrintMessage(int messageNumber); (returns void , takes one parameter).

int GetChoice(); (returns int , no parameters).

Listing 1.1 - Function Declaration, Definition, and Use:


Here’s the code written in a clear and clean format for better readability:

// Listing 1.1 - Demonstrates the use of function prototypes

#include <iostream.h>

// Define a new type


typedef unsigned short USHORT;

// Function prototype
USHORT FindArea(USHORT length, USHORT width);

int main() {
USHORT lengthOfYard;
USHORT widthOfYard;

Chapter - 1 | Modular Programming 4


USHORT areaOfYard;

// Get the dimensions of the yard from the user


cout << "\nHow wide is your yard? ";
cin >> widthOfYard;

cout << "\nHow long is your yard? ";


cin >> lengthOfYard;

// Calculate the area of the yard


areaOfYard = FindArea(lengthOfYard, widthOfYard);

// Display the result


cout << "\nYour yard is " << areaOfYard << " square feet
\n\n";

return 0;
}

// Function definition
USHORT FindArea(USHORT l, USHORT w) {
return l * w;
}

Code Explanation:

Prototype: Declared on line 5:

USHORT FindArea(USHORT length, USHORT width);

Definition: Starts on line 26:

USHORT FindArea(USHORT l, USHORT w) {


return l * w;
}

Chapter - 1 | Modular Programming 5


Usage in main() : The function is called on line 18:

areaOfYard = FindArea(lengthOfYard, widthOfYard);

Output Example:

How wide is your yard? 100


How long is your yard? 200
Your yard is 20000 square feet

Key Points from Analysis:

The prototype and definition must match in return type, function name, and
parameter types.

Parameter names in the prototype (e.g., length , width ) are optional but
improve readability.

Function arguments are passed in the declared order, not based on variable
names.

The function body is always enclosed in braces, even for single statements.

Analysis:
1. Prototype vs. Definition:

Prototype (line 5): Declares the function with its return type, name, and
parameter types.

USHORT FindArea(USHORT length, USHORT width);

Definition (line 26): Implements the function's logic.

USHORT FindArea(USHORT l, USHORT w) {


return l * w;
}

Chapter - 1 | Modular Programming 6


Both match in name, return type, and parameter types. Any mismatch
would result in a compiler error.

2. Difference Between Prototype and Definition:

The prototype ends with a semicolon and has no body.

The definition has the function body enclosed in braces {} .

3. Parameter Names:

The parameter names in the prototype ( length and width ) differ from those
in the definition ( l and w ).

Key Point: Parameter names in the prototype are for programmer clarity
and are not used during compilation.

Best practice: Use consistent names in both the prototype and the
definition to avoid confusion.

4. Argument Passing:

Arguments are passed to the function in the declared order, not by name.

For example:

areaOfYard = FindArea(lengthOfYard, widthOfYard);

If the arguments were reversed (e.g., FindArea(widthOfYard, lengthOfYard) ),


the function would treat widthOfYard as length and lengthOfYard as
width .

5. Function Body:

The body is always enclosed in braces {} , even if it contains only a single


statement.

return l * w;

6. Good Programming Style:

While parameter names in the prototype are optional, including them


improves clarity and matches the function's purpose, making the code

Chapter - 1 | Modular Programming 7


easier to understand.

1.1.1.2. Defining a Function:


Function Definition Components:
1. Function Header:

Similar to the function prototype, but parameter names are mandatory.

Does not end with a semicolon.

Syntax:

return_type function_name(type parameterName1, type par


ameterName2, ...);

2. Function Body:

Contains the logic of the function enclosed in braces {} .

Statements inside the body must end with semicolons.

The function itself ends with a closing brace, not a semicolon.

3. Return Statement:

Functions that return a value must use a return statement to provide the
value.

The return statement can appear anywhere in the function, but the
function should typically end with it.

If a function does not return a value, its return type must be explicitly
declared as void .

Key Rules for Function Definitions:


Parameter Names: All parameters in the function definition must have names.

Agreement with Prototype: The function definition must match the prototype
in:

Chapter - 1 | Modular Programming 8


Return type.

Function name.

Parameter types and order.

Return Type: Every function must have a return type (e.g., int , void ).

Examples of Function Definitions:


1. Function with Parameters and a Return Value:

long Area(long l, long w) {


return l * w;
}

Purpose: Calculates the area using length l and width w .

2. Function Without a Return Value (void):

void PrintMessage(int whichMsg) {


if (whichMsg == 0)
cout << "Hello.\n";
else if (whichMsg == 1)
cout << "Goodbye.\n";
else
cout << "I'm confused.\n";
}

Purpose: Prints a message based on the value of whichMsg .

Notes:
Functions do not require parameters, but if they have them, the prototype
does not need to include parameter names, only their types.

Good Practice: Always provide meaningful parameter names for clarity and
better readability.

Ensure every function has an explicit return type, even for void functions.

Chapter - 1 | Modular Programming 9


Function Statements:
1. Contents of a Function Body:

A function body can contain any number and any type of statements.

Common statements include variable declarations, conditional statements


( if , else ), loops ( for , while ), and function calls.

2. Limitations:

Function definitions cannot be nested. That means you cannot define one
function inside another.

However, a function can call another function, including itself (recursion).

3. Recursion:

A function calling itself is called recursion and will be covered later.

4. Function Size:

While there is no enforced limit to function size in C++, smaller functions


are generally better:

Easier to understand.

Easier to debug and maintain.

Often recommended to keep functions short enough to fit on a single


screen.

5. Best Practices for Functions:

Each function should perform one specific task that is easy to describe
and understand.

If a function becomes large, break it into smaller functions handling


individual tasks.

Example:
Instead of creating one large function to calculate and display a rectangle's
properties, divide it into smaller tasks:

Chapter - 1 | Modular Programming 10


1. Function to Calculate Area:

int CalculateArea(int length, int width) {


return length * width;
}

2. Function to Print Results:

void PrintResults(int area) {


cout << "The area is " << area << " square units.\n";
}

3. Main Function:

int main() {
int length = 10;
int width = 5;

int area = CalculateArea(length, width);


PrintResults(area);

return 0;
}

This modular approach makes each function easier to manage and reuse.

Execution of Functions:
1. Function Call and Execution:

When a function is called, the program's execution jumps to the first


statement inside the function (right after { ).

After the function's body is executed, control returns to the next line after
the function call.

2. Branching Within Functions:

Chapter - 1 | Modular Programming 11


Functions can use statements like if , else , and switch for decision-
making and branching.

3. Calling Other Functions:

A function can call another function or even call itself (recursion).

4. Execution Flow:

The figure represents the main loop calling separate modules (functions).

Each module performs its task and then returns control back to the main
loop.

5. Summary:

Functions modularize the program, making it easier to manage and debug.

The execution flow moves in and out of function bodies as needed.

1.2. Scope of Variables


A variable’s scope determines where it can be accessed and how long it remains
available within your program. There are two types of scopes in C++: Local and

Chapter - 1 | Modular Programming 12


Global.

1.2.1. Local Variables


Local Variables are declared within a function and can only be accessed
inside that function. They are created when the function starts executing and
are destroyed when the function finishes.

Parameters passed to the function are also local to that function and can be
used as local variables.

The scope of a variable is the block in which it is defined. If a variable is


declared inside a set of braces {} , it will only be available within that block.

Example: Using Local Variables and Parameters

#include <iostream>

float Convert(float); // Function prototype

int main() {
float TempFer; // Declare local variable for Fahrenheit
temperature
float TempCel; // Declare local variable for Celsius tem
perature

std::cout << "Please enter the temperature in Fahrenheit:


";
std::cin >> TempFer; // User input for Fahrenheit temper
ature
TempCel = Convert(TempFer); // Call the function with Te
mpFer as parameter
std::cout << "\nHere's the temperature in Celsius: ";
std::cout << TempCel << std::endl; // Output the Celsius
temperature

return 0;
}

Chapter - 1 | Modular Programming 13


float Convert(float TFer) {
float TCel; // Declare local variable for Celsius temper
ature
TCel = ((TFer - 32) * 5) / 9; // Convert Fahrenheit to C
elsius
return TCel; // Return the Celsius value
}

Output:

Please enter the temperature in Fahrenheit: 212


Here's the temperature in Celsius: 100

Please enter the temperature in Fahrenheit: 32


Here's the temperature in Celsius: 0

Please enter the temperature in Fahrenheit: 85


Here's the temperature in Celsius: 29.4444

Analysis:
Variables in main() : TempFer and TempCel are local variables that hold the
temperature in Fahrenheit and Celsius, respectively.

Passing Parameters: The Fahrenheit value ( TempFer ) is passed to the Convert()

function.

Local Variables in Convert() : Inside Convert() , a local variable TCel is used to


store the converted Celsius value. The parameter TFer is also a local variable
specific to the Convert() function.

When the function finishes executing, TCel goes out of scope, meaning it is no
longer available.

Key Points:
Local variables only exist within the function or block they are defined in.

Chapter - 1 | Modular Programming 14


For loop variables (like int i in a for loop) are also local to the loop.

When a function call is complete, any local variables inside it are destroyed
and no longer accessible.

Summary:
Local variables are an important concept in C++ as they help prevent name
conflicts by being restricted to specific areas of the program (functions or blocks).
This makes your code cleaner and easier to debug.

1.2.2. Global Variables


Variables declared outside of any function, typically at the top of the program,
have global scope. This means they are accessible from any function, including
main() . However, local variables with the same name as global variables do not

affect the global variable. If a function defines a local variable with the same name
as a global variable, the local variable "hides" the global variable within the scope
of that function. In such cases, the local variable takes precedence within the
function, while the global variable remains unchanged outside it.

Example: Demonstrating Global and Local Variables

#include <iostream>

void myFunction(); // function prototype

int x = 5, y = 7; // global variables

int main() {
std::cout << "x from main: " << x << "\n";
std::cout << "y from main: " << y << "\n\n";
myFunction();
std::cout << "Back from myFunction!\n\n";
std::cout << "x from main: " << x << "\n";
std::cout << "y from main: " << y << "\n";

Chapter - 1 | Modular Programming 15


return 0;
}

void myFunction() {
int y = 10; // local variable y

std::cout << "x from myFunction: " << x << "\n"; // Acce
ss global x
std::cout << "y from myFunction: " << y << "\n\n"; // Lo
cal y
}

Output:

x from main: 5
y from main: 7

x from myFunction: 5
y from myFunction: 10

Back from myFunction!

x from main: 5
y from main: 7

Analysis:
Global Variables: x and y are global variables, initialized to 5 and 7,
respectively.

Inside main() : The program prints the values of x and y (global variables)
before calling myFunction() .

Inside myFunction() : The function defines a local variable y with the value 10.
This hides the global y while inside the function. The global x is used
because no local x is defined in myFunction() .

Chapter - 1 | Modular Programming 16


After returning to main() , the values of the global variables x and y remain
unchanged.

Example: Variables Scoped Within a Block

#include <iostream>

void myFunc();

int main() {
int x = 5;
std::cout << "\nIn main x is: " << x;
myFunc();
std::cout << "\nBack in main, x is: " << x;
return 0;
}

void myFunc() {
int x = 8;
std::cout << "\nIn myFunc, local x: " << x << std::endl;

{
std::cout << "\nIn block in myFunc, x is: " << x;
int x = 9; // New block-scoped variable
std::cout << "\nVery local x: " << x;
}

std::cout << "\nOut of block, in myFunc, x: " << x << st


d::endl;
}

Output:

In main x is: 5
In myFunc, local x: 8

Chapter - 1 | Modular Programming 17


In block in myFunc, x is: 8
Very local x: 9
Out of block, in myFunc, x: 8
Back in main, x is: 5

Analysis:
Local Variable Scope: In main() , the local variable x is initialized to 5. This is
printed when the program starts.

Inside myFunc() , a new local variable x is created with the value 8.

Block Scope: A new x is created inside a block within myFunc() , which has the
value 9. This variable is only visible within that block. After the block ends,
this local x goes out of scope, and the variable x with the value 8 is used
again.

Caution About Global Variables:


While global variables are allowed in C++, they are often discouraged. This is
because global variables can be accessed and modified by any function, leading
to potential issues such as:

Unintended side effects: A function can change a global variable in a way that
is invisible to other functions, making bugs difficult to trace and fix.

Better Practice: It is generally recommended to use local variables wherever


possible and pass necessary values between functions using function
parameters rather than relying on global variables.

Scope Resolution Operator ( :: )


If a local variable has the same name as a global variable, you can still access the
global variable using the scope resolution operator :: . This tells the compiler to
use the global variable instead of the local one.

Example: Using the Scope Resolution Operator

#include <iostream>

Chapter - 1 | Modular Programming 18


float num = 42.8; // global variable

int main() {
float num = 26.4; // local variable
std::cout << "The value of num is: " << num << std::endl;
// Uses local num
std::cout << "The global value of num is: " << ::num << s
td::endl; // Uses global num
return 0;
}

Output:

The value of num is: 26.4


The global value of num is: 42.8

Explanation:
Local Variable: In the main() function, the local variable num is used, and its
value is printed as 26.4.

Global Variable: The scope resolution operator ::num tells the compiler to use
the global num , which has the value 42.8.

Summary:
Global Variables are accessible throughout the entire program, but they
should be used cautiously as they can lead to hard-to-debug issues.

Local Variables are only accessible within the function or block where they
are defined.

The scope resolution operator ( :: ) allows you to explicitly refer to a global


variable when a local variable with the same name exists.

1.3. Function Arguments

Chapter - 1 | Modular Programming 19


In C++, function arguments do not need to be of the same type. You can write a
function that accepts various types of arguments, such as integers, longs, or
characters. Additionally, you can pass expressions as arguments, including
constants, mathematical or logical expressions, or even function calls that return a
value.

Example: Multiple Arguments of Different Types


You can define a function that takes arguments of different types like this:

void myFunction(int a, long b, char c) {


// Function implementation
}

In this example, myFunction accepts an integer ( a ), a long integer ( b ), and a


character ( c ).

Using Functions as Parameters to Other Functions


It’s possible to pass one function as an argument to another function. While this is
legal in C++, it can sometimes lead to complicated and difficult-to-read code. If
the function calls are nested, it can be hard to determine the order of execution
and debug the code if something goes wrong.

Example: Function Calls Inside Arguments


Consider a situation where you have multiple functions, like double() , triple() ,
square() , and cube() , each of which returns a value. You might write a statement
like this:

Answer = double(triple(square(cube(myValue))));

This expression does the following:

1. cube(myValue) is called first and returns a result.

2. The result of cube() is passed to square() .

3. The result of square() is passed to triple() .

Chapter - 1 | Modular Programming 20


4. The result of triple() is passed to double() .

While this works, it can be difficult to read and understand. For instance, you may
not be sure of the exact order of operations—did the value get tripled before it
was squared? If the result is wrong, it will be hard to identify which function
caused the problem.

Better Approach: Using Intermediate Variables


A clearer approach is to break down the complex expression into smaller steps by
using intermediate variables. This makes the code more readable and
debuggable.

Example: Breaking Down the Expression

unsigned long myValue = 2;

unsigned long cubed = cube(myValue); // cubed = 8


unsigned long squared = square(cubed); // squared = 64
unsigned long tripled = triple(squared); // tripled = 196
unsigned long Answer = double(tripled); // Answer = 392

In this example:

1. The value of myValue is first cubed ( cube(myValue) ).

2. The result is then squared ( square(cubed) ).

3. The squared result is tripled ( triple(squared) ).

4. Finally, the result is doubled ( double(tripled) ).

By using intermediate variables ( cubed , squared , tripled ), the code is much easier
to follow. You can also inspect the intermediate results during debugging if
something goes wrong.

Key Takeaways:
Function arguments can be of various types and can even be expressions or
function calls.

Chapter - 1 | Modular Programming 21


Passing functions as arguments can make code hard to read and debug,
especially when functions are nested.

Using intermediate variables in cases of complex expressions helps improve


readability and makes debugging easier by allowing you to inspect each step
in the process.

1.4. Passing Arguments


1.4.1. Pass by Value
When you pass arguments to a function by value, a local copy of each argument
is created within the function. Any changes made to these local copies do not
affect the values of the variables in the calling function. This is known as passing
by value.

Example: Passing by Value


In the following example, two integers are passed to a swap() function, but since
they are passed by value, the original variables in main() are not affected by the
swap inside the function.

#include <iostream.h>

void swap(int x, int y); // function prototype

int main()
{
int x = 5, y = 10;

// Before swap
cout << "Main. Before swap, x: " << x << " y: " << y <<
"\n";

swap(x, y); // call the swap function

Chapter - 1 | Modular Programming 22


// After swap
cout << "Main. After swap, x: " << x << " y: " << y <<
"\n";

return 0;
}

void swap(int x, int y)


{
int temp;

// Before swap inside the function


cout << "Swap. Before swap, x: " << x << " y: " << y <<
"\n";

// Swap the values


temp = x;
x = y;
y = temp;

// After swap inside the function


cout << "Swap. After swap, x: " << x << " y: " << y <<
"\n";
}

Output:

Main. Before swap, x: 5 y: 10


Swap. Before swap, x: 5 y: 10
Swap. After swap, x: 10 y: 5
Main. After swap, x: 5 y: 10

Analysis:
Main function:

Chapter - 1 | Modular Programming 23


Two variables, x and y , are initialized to 5 and 10, respectively.

The initial values are printed before the swap() function is called.

Inside swap() function:

The values of x and y are printed. These values are still 5 and 10
because they were passed by value, meaning the swap() function is
working with copies of the variables, not the original variables from main() .

The values of x and y are swapped inside the function, and the new
swapped values (10 and 5) are printed.

Back in main():

After the swap() function finishes, the values of x and y in main() are
printed again. They are still the same as before (5 and 10), because the
swap inside swap() only affected the local copies, not the original
variables.

Key Point:
When passing by value, changes to the arguments in the function do not affect
the original values in the calling function. This can be useful when you do not
want the original values to be modified.

1.4.2. Pass by Reference


In C++, passing by reference means that the original object is passed into the
function, rather than a copy. This allows the function to modify the original
values. Passing by reference can be done in two ways: using pointers or
references. The result is the same, but the syntax differs.
In this example, we'll use references to pass the variables to the swap() function,
so the values can be modified directly.

Example: Passing by Reference (Using References)

#include <iostream.h>

Chapter - 1 | Modular Programming 24


void swap(int &x, int &y); // Function declaration with refe
rence parameters

int main()
{
int x = 5, y = 10;

// Before swap
cout << "Main. Before swap, x: " << x << " y: " << y <<
"\n";

swap(x, y); // Call swap function with references

// After swap
cout << "Main. After swap, x: " << x << " y: " << y <<
"\n";

return 0;
}

void swap(int &rx, int &ry) // Function definition with refe


rence parameters
{
int temp;

// Before swap inside the function


cout << "Swap. Before swap, rx: " << rx << " ry: " << ry
<< "\n";

// Swap the values


temp = rx;
rx = ry;
ry = temp;

// After swap inside the function


cout << "Swap. After swap, rx: " << rx << " ry: " << ry <

Chapter - 1 | Modular Programming 25


< "\n";
}

Output:

Main. Before swap, x: 5 y: 10


Swap. Before swap, rx: 5 ry: 10
Swap. After swap, rx: 10 ry: 5
Main. After swap, x: 10 y: 5

Analysis:
1. Main Function:

Two variables, x and y , are initialized with values 5 and 10.

The values are printed before calling the swap() function.

2. Inside swap() function:

The variables rx and ry are references to the original x and y .

When you pass variables by reference, you don’t need special operators to
refer to the original variables; rx and ry are just aliases.

The values are swapped inside the function.

The swapped values (10 and 5) are printed inside swap() .

3. Back in main():

After the function call, the values of x and y in main() are printed again.

Since x and y were passed by reference, they are directly modified


inside the swap() function.

The values are now swapped (10 and 5).

Key Point:
When you pass arguments by reference, any changes made inside the function
will directly affect the original variables in the calling function. This method is
useful when you want to modify the values of the variables passed to the function.

Chapter - 1 | Modular Programming 26


1.5. Return Values
Functions in C++ can return a value or be declared as void to indicate that they do
not return anything. When a function returns a value, the return keyword is used,
followed by the value or expression you want to return. For example:

return 5; // Returns the value 5


return (x > 5); // Returns 1 (true) or 0 (false), depe
nding on the condition
return (MyFunction()); // Returns the result of another funct
ion

Once the return statement is encountered, the function immediately exits, and no
further statements in the function are executed. It's legal to have multiple return
statements within a single function.

Example: Multiple Return Statements in a Function

#include <iostream.h>

int Doubler(int AmountToDouble); // Function declaration

int main()
{
int result = 0;
int input;

cout << "Enter a number between 0 and 10,000 to double:


";
cin >> input;

cout << "\nBefore doubler is called... ";


cout << "\ninput: " << input << " doubled: " << result <<
"\n";

Chapter - 1 | Modular Programming 27


result = Doubler(input); // Call the function and assign
the return value to result

cout << "\nBack from Doubler...\n";


cout << "\ninput: " << input << " doubled: " << result <<
"\n";

return 0;
}

int Doubler(int original)


{
if (original <= 10000)
return original * 2; // Return twice the original va
lue if <= 10,000
else
return -1; // Return -1 if the value is greater than
10,000
}

Output:

Enter a number between 0 and 10,000 to double: 9000


Before doubler is called...
input: 9000 doubled: 0
Back from Doubler...
input: 9000 doubled: 18000

Enter a number between 0 and 10,000 to double: 11000


Before doubler is called...
input: 11000 doubled: 0
Back from Doubler...
input: 11000 doubled: -1

Analysis:

Chapter - 1 | Modular Programming 28


1. Main Function:

The user is prompted to enter a number between 0 and 10,000.

The value is printed before calling the Doubler() function, and the result is
initially set to 0.

2. Doubler Function:

The function Doubler checks if the input is less than or equal to 10,000.

If true, it returns twice the input value.

If the input is greater than 10,000, it returns 1 to indicate an error.

The program returns the value immediately when the condition is met,
which stops further execution of the function.

3. Return Values:

The main() function prints the results before and after calling Doubler() .

If the input is 9,000, the output is 18,000 (since 9,000 * 2 = 18,000).

If the input is 11,000, which is greater than 10,000, the function returns 1.

Key Points:
The return keyword immediately exits the function and passes the value back
to the calling function.

You can have multiple return statements in a function, but only one of them
will be executed.

A void function does not return any value. If you want to return something,
you need to specify the return type (like int , double , etc.).

1.6. Default Parameters


In C++, default parameters allow a function to have optional arguments. If a
calling function does not pass an argument for a parameter that has a default
value, the default value will be used instead. This helps simplify function calls
when some parameters have common or default values.

Chapter - 1 | Modular Programming 29


Syntax for Default Parameters
A function prototype can specify default values for parameters. Here’s an
example:

long myFunction(int x = 50);

In this case, if no argument is passed when calling myFunction() , the parameter x

will default to 50. The function definition remains the same, but the prototype can
declare default values for one or more parameters.

If you don’t want to specify a name for the default parameter in the prototype, it
can be written as:

long myFunction(int = 50);

The name of the parameter in the prototype doesn’t have to match the name in the
function definition. What matters is the position of the argument and its default
value. Parameters can have default values, but any parameter without a default
value must come before any parameters with a default value. This means:

If Param3 has a default value, then Param2 must also have one.

If Param2 has a default value, Param1 must also have one.

Example: Default Parameters in Action

#include <iostream.h>

int AreaCube(int length, int width = 25, int height = 1);

int main()
{
int length = 100;
int width = 50;
int height = 2;
int area;

Chapter - 1 | Modular Programming 30


// Call AreaCube with all three parameters
area = AreaCube(length, width, height);
cout << "First area equals: " << area << "\n";

// Call AreaCube with only two parameters (height default


s to 1)
area = AreaCube(length, width);
cout << "Second time area equals: " << area << "\n";

// Call AreaCube with only the length (width defaults to


25, height defaults to 1)
area = AreaCube(length);
cout << "Third time area equals: " << area << "\n";

return 0;
}

int AreaCube(int length, int width, int height)


{
return (length * width * height);
}

Output:

First area equals: 10000


Second time area equals: 5000
Third time area equals: 2500

Analysis:
1. Function Declaration:
The function AreaCube() takes three integer parameters. The parameters width

and height have default values (25 and 1, respectively).

2. First Call:

Chapter - 1 | Modular Programming 31


All parameters ( length , width , and height ) are passed, so the function
computes the area as length * width * height , i.e., 100 * 50 * 2 = 10000 .

3. Second Call:

Only length and width are passed. The default value for height (1) is used.
The area is computed as 100 * 50 * 1 = 5000 .

4. Third Call:

Only length is passed. The default values for width (25) and height (1) are
used. The area is computed as 100 * 25 * 1 = 2500 .

Key Points:
Default Values: A default value is used when no argument is provided for that
parameter.

Order of Parameters: Parameters with default values must appear after


parameters without default values.

Multiple Default Parameters: You can specify default values for any or all
parameters, but once a parameter has a default, all following parameters must
also have default values.

Function Behavior: Parameters with default values can be omitted during the
function call, but the function will still work based on the provided or default
values.

1.7. Inline Functions


In C++, inline functions are used to improve the performance of small functions
by avoiding the overhead of a function call. Normally, when a function is called,
the program jumps to the function's instructions, executes them, and then returns
to the calling function. However, this jump has a small performance cost, which
can be avoided if the function is small (like just one or two lines of code).
An inline function allows the compiler to insert the function's code directly at the
place where it is called, eliminating the jump. This can make the program run
faster, especially if the function is very small and called frequently.

Chapter - 1 | Modular Programming 32


Syntax for Inline Functions
An inline function is defined using the inline keyword before the return type.
Here’s the syntax:

inline return_type function_name (type parameter1, type param


eter2, ...)
{
// function body
}

However, inline functions come with trade-offs. If the function is called many
times, the function's code gets copied into the calling code multiple times. This
can increase the size of the executable, and in such cases, the speed
improvement may not be worth the extra memory usage.

Rule of Thumb:
Inline small functions: Functions that are very small, such as those that
consist of one or two statements, are good candidates for being inline.

Avoid inline for larger functions: For more complex functions, inlining may
actually hurt performance because it increases the size of the program.

Example: Inline Function

#include <iostream.h>

inline int Double(int target);

int main()
{
int target;
cout << "Enter a number to work with: ";
cin >> target;
cout << "\n";

target = Double(target); // Function call

Chapter - 1 | Modular Programming 33


cout << "Target: " << target << endl;

target = Double(target); // Function call


cout << "Target: " << target << endl;

target = Double(target); // Function call


cout << "Target: " << target << endl;

return 0;
}

inline int Double(int target)


{
return 2 * target; // Inline function body
}

Output:

Enter a number to work with: 20


Target: 40
Target: 80
Target: 160

Analysis:
1. Function Declaration:
The Double function is declared as inline ( inline int Double(int target) ), meaning
the compiler will try to replace the function call with the code 2 * target
wherever it is called.

2. Function Calls:
On lines 15, 18, and 22, the Double function is called, but the compiler does not
create a traditional jump to the function. Instead, it directly inserts the
operation 2 * target at each of these calls.

3. Impact on Performance:

Chapter - 1 | Modular Programming 34


Since the function is small (only one line), inlining can improve performance by
avoiding the function call overhead. However, if Double were a large function,
inlining would increase the size of the program unnecessarily.

Conclusion:
Inline functions can help improve performance when the function body is
small and called frequently, but they should be used carefully. Inlining large
functions may increase the size of the program without significant
performance gains.

Explanation of Recursive Functions (C++ Example)


A recursive function is a function that calls itself directly or indirectly. The given
example is a mathematical function f(x) defined recursively for non-negative
integers:

Base Case:
f(0) = 0
This is the starting point, where the value of f(x)f(x) is directly known.

Recursive Case:
f(x) = 2f(x − 1) + x2f(x) = 2f(x − 1) + x2 , forx > 0x > 0
This defines f(x)in terms of f(x − 1).

Example Calculation:
F orf(3)
f(3) = 2f(2) + 32 = 2f(2) + 9

First, compute f(2):

f(2) = 2f(1) + 22 = 2f(1) + 4

Chapter - 1 | Modular Programming 35


Next, compute f(1):

f(1) = 2f(0) + 12 = 2(0) + 1 = 1

Now substitute back:


f(2) = 2(1) + 4 = 6
f(3) = 2(6) + 9 = 21

Implementing f(x) in C++:

#include <iostream>
#include <cmath> // For pow() function

// Recursive function definition


int f(int x) {
if (x == 0) { // Base case
return 0;
} else { // Recursive case
return 2 * f(x - 1) + pow(x, 2); // Recursive call
}
}

int main() {
int x;
std::cout << "Enter a non-negative integer: ";
std::cin >> x;

if (x < 0) {
std::cout << "Please enter a non-negative integer." <
< std::endl;
} else {
std::cout << "f(" << x << ") = " << f(x) << std::end
l;
}

Chapter - 1 | Modular Programming 36


return 0;
}

Explanation of the Code:


1. Base Case:
When x=0, the function directly returns 0.

2. Recursive Case:
When x > 0, the function calculates 2f(x − 1) + x2 by:
Calling itself with x − 1.

Computing x2 using pow(x, 2) .

3. Input Validation:
The program ensures that the user inputs a non-negative integer.

4. Example Run:

Input: 3

Output: f(3) = 21

Rules of Recursion:
1. Base Case: Always define a condition that stops the recursion (e.g. f(0) = 0)
2. Progress: Ensure recursive calls move closer to the base case (e.g. f(x − 1)
reduces as x)

3. Design: Assume the recursive call works as intended and focus on combining
results correctly.

4. Efficiency: Avoid redundant calculations (use memoization or dynamic


programming if needed).

Example: Recursive Function in C++


Here is how we might implement the recursive function f(x) in C++:

Chapter - 1 | Modular Programming 37


#include <iostream>
using namespace std;

// Recursive function definition


int f(int x) {
if (x == 0) // Base case
return 0;
else // Recursive case
return 2 * f(x - 1) + x * x;
}

int main() {
int result = f(3); // Call recursive function
cout << "f(3) = " << result << endl; // Output the resul
t
return 0;
}

Output:

f(3) = 21

Explanation:
The function f(int x) computes f(x) recursively by calling itself with x-1 until
it reaches the base case f(0) .

Each recursive call progresses toward the base case, and once the base case
is reached, the recursion starts unwinding, returning the computed values up
the call stack.

Conclusion:
Recursive functions are powerful tools for solving problems that can be
broken down into smaller, similar subproblems.

Chapter - 1 | Modular Programming 38


Always ensure you have a base case to stop the recursion, and make sure
each recursive step brings the problem closer to this base case.

More Recursive Problems and Their Implementation

C) The Euclidean Algorithm


The Euclidean Algorithm is used to find the Greatest Common Divisor (GCD) of
two integers mm and nn. The GCD is the largest positive integer that divides both
mm and nn without leaving a remainder.
Euclid's algorithm works as follows:

This is a recursive process that reduces the problem by subtracting the smaller
number from the larger number.
Recursive Implementation:

int gcd(int m, int n) {


if (m == n) return n; // Base case: if both
numbers are equal
else if (m > n) return gcd(m - n, n); // If m > n, subtr
act n from m
else return gcd(m, n - m); // If n > m, subt
ract m from n
}

Chapter - 1 | Modular Programming 39


D) Binary Search
Binary Search is an efficient way to search for an element xx in a sorted array. It
repeatedly divides the search interval in half. If the value of the search key is less
than the item in the middle, the search continues in the left half. Otherwise, it
continues in the right half.
Recursive Binary Search Implementation:

int find(float* a, int start, int stop, float x) {


if (start > stop) return -1; // Base cas
e: element not found
int mid = (start + stop) / 2; // Find th
e middle index
if (x == a[mid]) return mid; // If elem
ent is found at mid
if (x < a[mid]) return find(a, start, mid - 1, x); // Se
arch in left half
else return find(a, mid + 1, stop, x); // Search i
n right half
}

The function find takes in a sorted array a , and the start and stop indices for
the search range.

If x is equal to the middle element a[mid] , it returns the index mid .

If x is smaller, the search continues in the left half; otherwise, it searches in


the right half.

E) The Tower of Hanoi


The Tower of Hanoi is a classic example used to demonstrate recursion. The
puzzle consists of three pegs, and initially, disks of different sizes are stacked on
one peg. The goal is to move all the disks to another peg, following these rules:

1. Only one disk can be moved at a time.

2. A disk can only be moved to the top of a peg if it is smaller than the disk
already on that peg.

Chapter - 1 | Modular Programming 40


The recursive solution works as follows:

1. Move disks from the source peg to the auxiliary peg.


N−1N-1

2. Move the largest disk from the source peg to the destination peg.

3. Move the disks from the auxiliary peg to the destination peg.
N−1N-1

Recursive Implementation of Tower of Hanoi:

#include <iostream.h>
#include <conio.h>

void Form(int N, char pegA, char pegB, char pegC) {


if (N == 1) {
cout << "Move top disk from peg " << pegA << " to peg
" << pegC << endl;
} else {
Form(N - 1, pegA, pegC, pegB); // Step 1: M
ove N-1 disks from A to B
cout << "Move top disk from peg " << pegA << " to peg
" << pegC << endl; // Step 2: Move Nth disk from A to C
Form(N - 1, pegB, pegA, pegC); // Step 3: M
ove N-1 disks from B to C
}
}

Chapter - 1 | Modular Programming 41


int main() {
int N;
cout << "How many disks? ===> ";
cin >> N;
Form(N, 'A', 'B', 'C'); // Solve the puzzle with N disks
getch();
return 0;
}

Base Case: If there is only 1 disk, simply move it to the destination peg.

Recursive Case: For more than 1 disk, move the top disks to the auxiliary peg,
then move the largest disk to the destination peg, and finally move the disks
from the auxiliary peg to the destination peg.
N−1N-1
N−1N-1

Summary of Recursive Problems


Euclidean Algorithm: A recursive way to find the greatest common divisor
(GCD) of two numbers by reducing the problem using subtraction.

Binary Search: A recursive algorithm for searching an element in a sorted


array by dividing the search space in half at each step.

Tower of Hanoi: A puzzle that demonstrates recursion by reducing a large


problem (moving disks) into smaller sub-problems (moving disks).
NN
N−1N-1

When to Use Recursion


Recursion is powerful and elegant for problems that have smaller sub-problems
of the same nature. It is often inefficient for simple problems that can be solved
iteratively, especially in terms of time complexity and space complexity due to
the overhead of managing function calls and the call stack.

Chapter - 1 | Modular Programming 42


However, recursion is essential for problems that naturally fit into the divide-and-
conquer approach, like binary search, tree traversal, and mathematical puzzles
like the Tower of Hanoi.

Chapter - 1 | Modular Programming 43

You might also like