Chapter - 1 Cp2 (Notion)
Chapter - 1 Cp2 (Notion)
Chapter - 1 | Modular
Programming
Acts on data.
4. Execution Flow:
After the function completes, execution resumes on the next line after the
function call.
5. Design of Functions:
6. Types of Functions:
2. Function Prototype:
3. Calling Functions:
This ensures the compiler knows the function details before it is used in the
program.
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.
3. Function Prototypes:
Prototypes for built-in functions are included in library files (e.g., via
#include ).
Syntax:
4. Naming Parameters:
Example:
5. Examples of Prototypes:
#include <iostream.h>
// Function prototype
USHORT FindArea(USHORT length, USHORT width);
int main() {
USHORT lengthOfYard;
USHORT widthOfYard;
return 0;
}
// Function definition
USHORT FindArea(USHORT l, USHORT w) {
return l * w;
}
Code Explanation:
Output Example:
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.
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:
5. Function Body:
return l * w;
Syntax:
2. Function Body:
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 .
Agreement with Prototype: The function definition must match the prototype
in:
Function name.
Return Type: Every function must have a return type (e.g., int , void ).
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.
A function body can contain any number and any type of statements.
2. Limitations:
Function definitions cannot be nested. That means you cannot define one
function inside another.
3. Recursion:
4. Function Size:
Easier to understand.
Each function should perform one specific task that is easy to describe
and understand.
Example:
Instead of creating one large function to calculate and display a rectangle's
properties, divide it into smaller tasks:
3. Main Function:
int main() {
int length = 10;
int width = 5;
return 0;
}
This modular approach makes each function easier to manage and reuse.
Execution of Functions:
1. Function Call and Execution:
After the function's body is executed, control returns to the next line after
the function call.
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:
Parameters passed to the function are also local to that function and can be
used as local variables.
#include <iostream>
int main() {
float TempFer; // Declare local variable for Fahrenheit
temperature
float TempCel; // Declare local variable for Celsius tem
perature
return 0;
}
Output:
Analysis:
Variables in main() : TempFer and TempCel are local variables that hold the
temperature in Fahrenheit and Celsius, respectively.
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.
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.
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.
#include <iostream>
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";
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
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() .
#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;
}
Output:
In main x is: 5
In myFunc, local x: 8
Analysis:
Local Variable Scope: In main() , the local variable x is initialized to 5. This is
printed when the program starts.
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.
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.
#include <iostream>
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:
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.
Answer = double(triple(square(cube(myValue))));
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.
In this example:
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.
#include <iostream.h>
int main()
{
int x = 5, y = 10;
// Before swap
cout << "Main. Before swap, x: " << x << " y: " << y <<
"\n";
return 0;
}
Output:
Analysis:
Main function:
The initial values are printed before the swap() function is called.
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.
#include <iostream.h>
int main()
{
int x = 5, y = 10;
// Before swap
cout << "Main. Before swap, x: " << x << " y: " << y <<
"\n";
// After swap
cout << "Main. After swap, x: " << x << " y: " << y <<
"\n";
return 0;
}
Output:
Analysis:
1. Main Function:
When you pass variables by reference, you don’t need special operators to
refer to the original variables; rx and ry are just aliases.
3. Back in main():
After the function call, the values of x and y in main() are printed again.
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.
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.
#include <iostream.h>
int main()
{
int result = 0;
int input;
return 0;
}
Output:
Analysis:
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.
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 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.).
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:
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.
#include <iostream.h>
int main()
{
int length = 100;
int width = 50;
int height = 2;
int area;
return 0;
}
Output:
Analysis:
1. Function Declaration:
The function AreaCube() takes three integer parameters. The parameters width
2. First Call:
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.
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.
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.
#include <iostream.h>
int main()
{
int target;
cout << "Enter a number to work with: ";
cin >> target;
cout << "\n";
return 0;
}
Output:
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:
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.
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
#include <iostream>
#include <cmath> // For pow() function
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;
}
2. Recursive Case:
When x > 0, the function calculates 2f(x − 1) + x2 by:
Calling itself with x − 1.
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.
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.
This is a recursive process that reduces the problem by subtracting the smaller
number from the larger number.
Recursive Implementation:
The function find takes in a sorted array a , and the start and stop indices for
the search range.
2. A disk can only be moved to the top of a peg if it is smaller than the disk
already on that peg.
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
#include <iostream.h>
#include <conio.h>
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