0% found this document useful (0 votes)
3 views38 pages

C Programming For Problem Solving Module 4

Chapter 4 covers C functions, defining them as self-contained blocks of code that perform specific tasks, and discusses their syntax, declaration, definition, and calling methods. It emphasizes modular programming, outlining its advantages such as code reusability and improved maintainability, and distinguishes between user-defined and built-in functions. The chapter also explains function return types, arguments, and various ways to pass parameters, along with examples illustrating different function categories.

Uploaded by

nehanikita17
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)
3 views38 pages

C Programming For Problem Solving Module 4

Chapter 4 covers C functions, defining them as self-contained blocks of code that perform specific tasks, and discusses their syntax, declaration, definition, and calling methods. It emphasizes modular programming, outlining its advantages such as code reusability and improved maintainability, and distinguishes between user-defined and built-in functions. The chapter also explains function return types, arguments, and various ways to pass parameters, along with examples illustrating different function categories.

Uploaded by

nehanikita17
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

Chapter 4

C Functions

A function can be defined as:

• A piece of code or group of statements that perform a specific task.

• A self-contained block of code that performs a particular task.

• A piece of code that takes some input, performs computations on those inputs, and provides an output.

• An independent program module designed to carry out a particular task.

4.1 Introduction

A function in C is a set of statements that, when called, perform specific tasks. Functions are the basic building blocks of a C program, providing
modularity and code reusability. The statements in a function are enclosed within {} braces. Functions in C are also known as subroutines or procedures
in other programming languages.

4.2 Syntax of Functions in C

The syntax of functions in C can be divided into three aspects:

1. Function Declaration

2. Function Definition

3. Function Call

4.2.1 Function Declaration

A function declaration specifies the function name, return type, and the number and type of its parameters. It informs the compiler that a function
with the given name is defined elsewhere in the program.

Syntax

return_type function_name(parameter_1, parameter_2);

The parameter names are optional in the function declaration.

108
CHAPTER 4. C FUNCTIONS 109

Examples

// Function declaration with parameter names


int sum(int a, int b);

// Function declaration without parameter names


int sum(int, int);

Note: A function in C must be declared globally before it is called.

4.2.2 Function Definition

The function definition contains the actual statements to be executed when the function is called. In most cases, the function is defined and declared in
a single step.

Syntax

return_type function_name(parameter1_type parameter1_name, parameter2_type parameter2_name) {


// Function body
}

4.2.3 Function Call

A function call is a statement that directs the program control to execute the function. The function name and parameters are used in the function call.
For example:

#include <stdio.h>

int sum(int a, int b) {


return a + b;
}

int main() {
int add = sum(10, 30);
CHAPTER 4. C FUNCTIONS 110

printf("Sum is: %d", add);


return 0;
}

Output:

Sum is: 40

Note: A function call is necessary to execute the function. Without it, the function statements will not run.

4.3 Function Return Types

The return type of a function specifies the type of value that will be returned after execution. When no value needs to be returned, the void type can
be used.

Example

int func(parameter_1, parameter_2);

Note: A C function can return only one value. To return multiple values, pointers or structures can be used.

4.4 Function Arguments

Function arguments, also known as parameters, are data passed to the function when it is called.

Example

int function_name(int var1, int var2);

4.4.1 Features

• A function is a block of code that can be reused multiple times within a program.

• To use a function, we need to call it explicitly.

• Function declaration includes the function_name, return_type, and parameters.

• Function definition includes the body of the function.

• There are two types of functions: user-defined functions and library functions.

• Function arguments can be passed in two ways: call by value and call by reference.

4.5 Modular Programming

Modular programming is a technique used to organize a large program into smaller, independent segments called modules. Each module is a separately
named and individually callable program unit. This approach follows the principle of “divide-and-conquer”, allowing complex problems to be broken
down into manageable parts.

4.5.1 Key Features of Modular Programming

• Code Reusability: Modules can be reused across multiple programs or projects, reducing development time and effort.

• Improved Maintainability: Since modules are independent, fixing bugs or making changes becomes easier and less prone to errors.

• Enhanced Readability: Breaking a program into modules improves the clarity and structure of the code, making it easier to understand.

• Independent Development: Different modules can be developed and tested independently, allowing parallel development and better resource
utilization.

• Encapsulation: Modules can hide their internal details from other parts of the program, promoting data security and reducing dependencies.

• Ease of Debugging: Isolating issues becomes simpler as each module can be tested and debugged individually.
CHAPTER 4. C FUNCTIONS 111

4.5.2 Steps in Modular Programming

1. Problem Analysis: Break the problem into smaller sub-problems or tasks.

2. Module Design: Define each module’s functionality, inputs, and outputs.

3. Coding: Implement each module independently.

4. Testing: Test each module in isolation to ensure it works as intended.

5. Integration: Combine all modules to form the complete program and ensure they work seamlessly together.

4.5.3 Advantages of Modular Programming

• Encourages a systematic approach to program design.

• Promotes teamwork by allowing developers to work on separate modules.

• Facilitates scalability by making it easier to add new functionality.

• Reduces redundancy by centralizing commonly used functions in a single module.

4.5.4 Conclusion

Modular programming simplifies software development by promoting a structured, organized approach to coding. It enhances productivity, maintainability,
and scalability, making it a preferred methodology for building robust and efficient programs.

4.6 Types of Functions

There are two main types of functions in C:

1. Library functions / Pre-defined functions / Standard functions / Built-in functions

2. User-Defined Functions

Difference Between User-Defined and Built-In Functions


User-Defined Function Built-In Function
These are requirement-based functions. These are pre-defined functions.
It is provided by the user. It is provided by the developers.
The names of the functions can be changed. The names of the functions cannot be changed.
These are part of the program and are called during compile time. These are part of the header file and are called during run time.
Examples: isprime( ), fibonacci( ) Examples: printf( ), scanf( ), cos( ), sin( )

4.6.1 Library Functions

Library functions are built-in functions provided by the compiler. They are directly usable without being defined by the programmer.

or

These functions are pre-defined in the library of the C compiler and are frequently used in C programs. They are written by the designers of the C
compiler. C supports many built-in functions such as:

• Mathematical functions

• String manipulation functions


CHAPTER 4. C FUNCTIONS 112

• Input and output functions

• Memory management functions

• Error handling functions

Examples: printf(), scanf(), pow(x, y), sqrt(x), etc.

Example

#include <math.h>
#include <stdio.h>

int main() {
double number = 49;
double squareRoot = sqrt(number);
printf("The Square root of %.2lf = %.2lf", number, squareRoot);
return 0;
}

Output:

The Square root of 49.00 = 7.00

4.6.2 User-defined Functions

These functions are written by programmers to perform specific tasks. They are not readily available and are created to serve a programmer’s custom
requirements. or User-defined functions are created by the programmer and can be tailored to specific needs.

Example

#include <stdio.h>

int sum(int a, int b) {


return a + b;
}

int main() {
int a = 30, b = 40;
int res = sum(a, b);
printf("Sum is: %d", res);
return 0;
}

Output:

Sum is: 70

Advantages of Functions in C

Functions in C are a highly useful feature of the language, offering several advantages as outlined below:

• Better memory utilization: Functions reduce the repetition of the same statements in a program.

• Reusability: Functions enhance code readability by providing modularity to the program.

• Simplified debugging: Functions can be called as many times as needed without any fixed limit.

• Easier maintenance: Functions help reduce the size of the program.

• Enhanced data protection: Once a function is declared, it can be reused without needing to consider its internal workings.
CHAPTER 4. C FUNCTIONS 113

Disadvantages of Functions in C

Despite their numerous benefits, functions in C also have some disadvantages:

• Functions cannot return multiple values directly.

• There is memory and time overhead due to stack frame allocation and transfer of program control.

4.7 User-Defined Functions in C

A user-defined function in C is a type of function defined by the programmer to perform a specific task. These functions provide code reusability
and modularity, making programs more efficient and easier to maintain. Unlike built-in functions, their functionality is specified by the user, and no
additional header files are required for their usage.

4.7.1 Components of a User-Defined Function

A user-defined function in C can be divided into the following components:

• Function Prototype: Specifies the function’s name, parameters, and return type to inform the compiler about its existence.

• Function Definition: Contains the actual implementation of the function, including the statements to be executed.

• Function Call: Transfers control to the function, passing necessary arguments.

4.7.2 Function Prototype

A function prototype, also known as a function declaration, specifies the function’s name, parameters, and return type without containing its body. It
informs the compiler about the function’s existence.

Syntax:

return_type function_name(type1 arg1, type2 arg2, ... typeN argN);

Alternatively, argument names can be omitted:

return_type function_name(type1, type2, ... typeN);

4.7.3 Function Definition

The function definition includes the actual implementation of the function, enclosed within {} braces.

Syntax:

return_type function_name(type1 arg1, type2 arg2, ...) {


// Function body
// Return value if any
}

Components of Function Definition

1. Function Parameters: Values passed to the function by the caller. Parameters must match in type and number between the call and definition.

2. Function Body: Statements within {} braces that execute when the function is called.

3. Return Value: The value returned to the caller. If no value is returned, the function type is void.
CHAPTER 4. C FUNCTIONS 114

Passing Parameters to Functions

In C, there are different ways in which parameter data can be passed into and out of methods and functions. Let us assume that a function B() is
called from another function A(). In this case, A is called the caller function and B is called the called function or callee function. The arguments
which A sends to B are called actual arguments, and the parameters of B are called formal arguments.

Terminology

• Formal Parameter: A variable and its type as it appears in the prototype of the function or method.

• Actual Parameter: The variable or expression corresponding to a formal parameter that appears in the function or method call in the calling
environment.

Modes

• IN: Passes information from the caller to the callee.

• OUT: Callee writes values to the caller.

• IN/OUT: The caller tells the callee the value of the variable, which the callee may update.

Parameter passing techniques in C, such as pass by value and pass by reference, are fundamental for controlling data flow.

Parameters can be passed to functions in two ways:

1. Pass by Value or Call by Value: : A copy of the argument is passed, and changes in the function do not affect the original value.

2. Pass by Reference or Call by Reference: The address of the argument is passed, allowing changes in the function to reflect in the original
variable.

[Link] by Value

In this method, the values of actual parameters are copied to the formal parameters. Changes inside the function do not affect the original values.

Example

#include <stdio.h>

void swap(int var1, int var2) {


int temp = var1;
var1 = var2;
var2 = temp;
}

int main() {
int var1 = 3, var2 = 2;
printf("Before swap: %d, %d\n", var1, var2);
swap(var1, var2);
printf("After swap: %d, %d", var1, var2);
return 0;
}

Output:

Before swap: 3, 2
After swap: 3, 2

Note: If the function call is present after the function definition, the prototype can be omitted.
CHAPTER 4. C FUNCTIONS 115

4.7.4 Function Call

A function call is used to execute a user-defined function. Arguments are passed inside parentheses.

Syntax:

function_name(arg1, arg2, ... argN);

General Syntax:

function_name(parameter_list);

Examples of Function Calls:

diff(a, b); // Function call with parameters


diff(); // Function call without parameters

• The method of calling a function to achieve a specific task is called a function call.

• A function call is defined as the function name followed by a semicolon.

• A function call is essentially invoking a function at the required place in the program to perform a specific task.

Categories of Functions

1. No arguments and no return value

2. No arguments with return value

3. With arguments and without return value

4. With arguments and with return value

Example:

// C Program to illustrate a user-defined function


#include <stdio.h>

// Function prototype
int sum(int, int);

// Function definition
int sum(int x, int y) {
return x + y;
}

// Driver code
int main() {
int x = 10, y = 11;
int result = sum(x, y);
printf("Sum of %d and %d = %d", x, y, result);
return 0;
}

Output:

Sum of 10 and 11 = 21
CHAPTER 4. C FUNCTIONS 116

Examples of Function Categories

1. No Arguments and No Return Value

• When a function has no arguments, it does not receive any data from the calling function.

• Similarly, when it does not return a value, the calling function does not receive any data from the called function.

Example:

[language=C]
#include<stdio.h>
void sum(void);
int main() {
sum();
}
void sum() {
int a = 10, b = 20, sum = 0;
sum = a + b;
printf("Sum = %d", sum);
}

Output:

Sum = 30

2. No Arguments with Return Value

• The calling function does not send any data to the called function but accepts the return value.

Example:

[language=C]
#include<stdio.h>
int sum(void);
int main() {
int s;
s = sum();
printf("Sum = %d", s);
}
int sum() {
int a, b, sum = 0;
printf("Enter a and b: ");
scanf("%d %d", &a, &b);
sum = a + b;
return sum;
}

Output:

Enter a and b:
10 20
Sum = 30

3. With Arguments and Without Return Value

• The calling function provides input to the called function.

• The called function does not return any values back.

Example:
CHAPTER 4. C FUNCTIONS 117

[language=C]
#include<stdio.h>
void sum(float, float);
int main() {
float x, y;
printf("Enter x and y: ");
scanf("%f %f", &x, &y);
sum(x, y);
}
void sum(float a, float b) {
float s = a + b;
printf("Sum = %f", s);
}

Output:

Enter x and y:
1.5 2.5
Sum = 4.000000

4. With Arguments and With Return Value

• The calling function sends data to the called function and also accepts a return value.

Example:

[language=C]
#include<stdio.h>
int sum(int, int);
int main() {
int x, y, c;
printf("Enter x and y: ");
scanf("%d %d", &x, &y);
c = sum(x, y);
printf("Sum = %d", c);
}
int sum(int a, int b) {
return a + b;
}

Output:

Enter x and y:
10 20
Sum = 30

Passing Arrays to a Function

To process arrays in a large program, they can be passed to functions in two ways:

• Passing individual elements

• Passing the entire array

Passing Individual Elements

Example:
CHAPTER 4. C FUNCTIONS 118

[language=C]
#include<stdio.h>
int square(int);
int main() {
int num[5] = {2, 4, 6, 8, 10}, i;
for (i = 0; i < 5; i++) {
square(num[i]);
}
}
int square(int n) {
int sq = n * n;
printf("%d ", sq);
}

Output:

4 16 36 64 100

Passing the Entire Array

Example:

[language=C]
#include<stdio.h>
void modify(int[]);
int main() {
int a[5] = {10, 20, 30, 40, 50}, i;
modify(a);
printf("Elements:\n");
for (i = 0; i < 5; i++) {
printf("%d\t", a[i]);
}
}
void modify(int x[]) {
for (int i = 0; i < 5; i++) {
x[i] = x[i] + 5;
}
}

Output:

15 25 35 45 55

Passing Strings to a Function

Strings are treated as character arrays in C. The rules for passing strings to functions are similar to those for arrays:

• The string must be declared as a formal argument of the function.

• The function prototype must indicate the argument as a string.

• The call must pass the string array name without subscripts.

Example:

[language=C]
#include<stdio.h>
void display(char[]);
int main() {
char str[] = "students";
CHAPTER 4. C FUNCTIONS 119

display(str);
}
void display(char str[]) {
printf("String is: %s", str);
}

Output:

String is: students

4.7.5 Pass by Reference

In this method, the memory addresses of actual parameters are passed. Changes made inside the function affect the original values.

Example

#include <stdio.h>

void swap(int *var1, int *var2) {


int temp = *var1;
*var1 = *var2;
*var2 = temp;
}

int main() {
int var1 = 3, var2 = 2;
printf("Before swap: %d, %d\n", var1, var2);
swap(&var1, &var2);
printf("After swap: %d, %d", var1, var2);
return 0;
}

Output:

Before swap: 3, 2
After swap: 2, 3

2. Pass by Pointers

This technique uses a pointer. In this method, the memory address (pointer) of a variable is passed rather than the actual value. This allows the
function to access and modify the content at that particular memory location.

Example: Pass By Pointers

#include <stdio.h>

// Function to modify the value passed as a pointer


void modifyVal(int* myptr)
{
// Access and modify the value pointed by myptr
*myptr = *myptr + 5;
}

int main()
{
int x = 5;
int* myptr = &x;

// Passing the pointer to the function


CHAPTER 4. C FUNCTIONS 120

modifyVal(myptr);

// Printing the modified value of x


printf("Modified value of x is: %d\n", x);
return 0;
}

Output:

Modified value of x is: 10

4.7.6 Shortcomings of Pass By Pointers:

• Pointers can be null, leading to issues if not properly checked.

• Changes made by one pointer affect other pointers pointing to the same memory location.

• Effective memory management is required using functions like malloc and free.

Other Methods of Parameter Passing

These techniques are older and were used in earlier programming languages like Pascal, Algol, and Fortran. These are not applicable in high-level
languages.

1. Pass By Result

This method uses out-mode semantics. Before control is transferred back to the caller, the value of the formal parameter is transmitted back to the
actual parameter. This method is also called call by result.

2. Pass By Value-Result

This method uses in/out-mode semantics. It is a combination of Pass By Value and Pass By Result. Before control is transferred back to the caller, the
value of the formal parameter is transmitted back to the actual parameter.

3. Pass By Name

This technique is used in programming languages such as Algol. The symbolic name of a variable is passed, allowing it to be accessed and updated.
For example:

procedure double(x);
real x;
begin
x := x * 2;
end;

Implications of Pass By Name:

• The argument expression is re-evaluated each time the formal parameter is passed.

• The procedure can change the values of variables used in the argument expression.

4.7.7 Advantages of User-Defined Functions

• Avoids code duplication and promotes code reusability.

• Simplifies debugging and testing by breaking tasks into smaller, manageable units.

• Reduces complexity through the divide-and-conquer approach.

• Enhances readability and maintainability.

• Allows hiding implementation details and reusing functions across programs.


CHAPTER 4. C FUNCTIONS 121

Iteration Recursion

Allows a set of instructions to be repeat- The statement in the body of a function


edly executed. calls itself.

Initialization, condition, and updation Only the termination condition is speci-


are present. fied.

Applicable to iterative statements. Applicable to functions.

The code size is larger. The code size is reduced.

Processes overhead due to repeated


No overhead of repeated function calls.
function calls.

Table 4.1: Comparison between Iteration and Recursion

4.7.8 Difference Between Iteration and Recursion

Program to Find GCD and LCM of Two Numbers Using Functions

Code

/* Program to find GCD and LCM of two numbers */


#include<stdio.h>

int hcf(int, int);

int main()
{
int x, y, gcd, lcm;
printf("Enter two numbers: ");
scanf("%d%d", &x, &y);
gcd = hcf(x, y);
lcm = (x * y) / gcd;
printf("GCD = %d\n", gcd);
printf("LCM = %d\n", lcm);
return 0;
}

int hcf(int x, int y)


{
if (x == 0)
return y;
while (y != 0)
{
if (x > y)
x = x - y;
else
y = y - x;
}
return x;
}

Output

Enter two numbers:


12 8
CHAPTER 4. C FUNCTIONS 122

GCD = 4
LCM = 24

4.8 Recursion

Recursion is a method of solving problems where the solution to a problem depends on solutions to smaller instances of the same problem. A recursive
function is a function that calls itself during its execution.

In C programming language, you may have heard of the concept of recursion. Recursion is often considered difficult and complex to understand and
implement.

What is Recursion in C?

Recursion is the process of a function calling itself repeatedly until a given condition is satisfied. A function that calls itself directly or indirectly is
called a recursive function, and such function calls are referred to as recursive calls.

In C, recursion is used to solve complex problems by breaking them down into simpler sub-problems. We can solve large numbers of problems using
recursion in C, such as calculating the factorial of a number, generating a Fibonacci series, generating subsets, etc.

Types of Recursion

There are two types of recursion:

• Direct Recursion: A recursive function that invokes itself is said to have direct recursion. For example, the factorial function calls itself, hence
it is called direct recursion.

• Indirect Recursion: A function that calls another function which in turn calls another function, and so on, is said to have indirect recursion.

4.8.1 Recursive Functions in C

A function that calls itself is called a Recursive Function. Recursive functions contain a call to themselves somewhere in the function body. These
functions can also contain multiple recursive calls.

Elements of a Recursive Function

Any recursive function has two elements:

1. Base Case:

• The statement that solves the problem without further recursion.

• Every recursive function must have at least one base case.

• It serves as a terminating condition and provides the solution when reached.

2. General Case:

• The statement that reduces the size of the problem.

• This is done by calling the same function with a reduced size.


CHAPTER 4. C FUNCTIONS 123

4.8.2 Basic Structure of Recursive Functions

The basic syntax structure of recursive functions in C is:

type function_name (args) {


// function statements
// base condition
// recursion case (recursive call)
}

4.8.3 Example: C Program to Implement Recursion

The following C program demonstrates recursion to calculate the sum of the first N natural numbers:

#include <stdio.h>

int nSum(int n)
{
// base condition to terminate the recursion when N = 0
if (n == 0) {
return 0;
}

// recursive case / recursive call


int res = n + nSum(n - 1);

return res;
}

int main()
{
int n = 5;
// calling the function
int sum = nSum(n);
printf("Sum of First %d Natural Numbers: %d", n, sum);
return 0;
}

Output:
Sum of First 5 Natural Numbers: 15

Fundamentals of C Recursion for the example

The fundamental of recursion consists of two key elements essential for any recursive function:
CHAPTER 4. C FUNCTIONS 124

Recursion or General Case

The recursion case refers to the recursive call present in the recursive function. It determines the type of recursion and how the problem will be divided
into smaller sub-problems. For example, in the function nSum(), the recursion case is:

int res = n + nSum(n − 1);

This can be represented mathematically as a recurrence relation:

f (N ) = N + f (N − 1)

Base Condition

The base condition specifies when the recursion will terminate. It defines the exit point for recursion. For the function nSum(), the base condition is:

if (n == 0) return 0;

It is important to define the base condition before the recursion case, otherwise the recursion might continue indefinitely.

How Recursion Works in C?

Let’s walk through the flow of the nSum() function for n = 5:

nSum(5) = 5 + nSum(4)

nSum(4) = 4 + nSum(3)
CHAPTER 4. C FUNCTIONS 125

nSum(3) = 3 + nSum(2)

nSum(2) = 2 + nSum(1)

nSum(1) = 1 + nSum(0)

Finally, when n = 0, the base condition is reached and nSum(0) = 0, thus:

nSum(5) = 5 + 4 + 3 + 2 + 1 + 0 = 15

The recursion terminates and the final result, 15, is returned.

4.8.4 Memory Allocation for C Recursive Function

In C, memory for function calls is managed via the stack. When a recursive function is called, a new stack frame is created for each function call. Each
time a recursive call occurs, a new stack frame is pushed onto the stack, and when the function returns, the stack frame is destroyed.

4.8.5 Stack Overflow

If a recursive function goes on indefinitely, it may exhaust the memory allocated for the stack. This results in a stack overflow, which is a common
error in recursion.

4.8.6 Examples of Recursion in C

Factorial Function Using Recursion

In general, the recursive function for the factorial problem can be written as:

5! = 5 × 4!

4! = 4 × 3!

3! = 3 × 2!

2! = 2 × 1!

1! = 1 × 0!

0! = 1 (Base Case)

Calculations:

1! = 1 × 0! = 1 × 1 = 1

2! = 2 × 1! = 2 × 1 = 2

3! = 3 × 2! = 3 × 2 = 6

4! = 4 × 3! = 4 × 6 = 24

5! = 5 × 4! = 5 × 24 = 120

The recursive definition of the factorial function is:



1, if n = 0 (Base Case)


n! =

n × fact(n − 1),

otherwise (General Case)

Limitations of Recursion

Recursive solutions may involve extensive overhead because they use function calls.
Each time a call is made, memory allocation is used, and if recursion is deep, the program may run out of memory.

Example Programs

Factorial Using Recursion

// C Program to Find Factorial Using Recursion


#include<stdio.h>
CHAPTER 4. C FUNCTIONS 126

int fact(int);
void main() {
int n, res;
printf("Enter the number to find its factorial\n");
scanf("%d", &n);
res = fact(n);
printf("Factorial of %d = %d", n, res);
}
int fact(int n) {
if (n == 0)
return 1;
else
return (n * fact(n - 1));
}

Fibonacci Series Using Recursion

//C Program to Generate Fibonacci Series Using Recursion


#include<stdio.h>
int Fibonacci(int);
void main() {
int n, i = 0, c;
printf("Enter the number of terms\n");
scanf("%d", &n);
printf("Fibonacci series\n");
for (c = 1; c <= n; c++) {
printf("%d\n", Fibonacci(i));
i++;
}
}
int Fibonacci(int n) {
if (n == 0)
return 0;
else if (n == 1)
return 1;
else
return (Fibonacci(n - 1) + Fibonacci(n - 2));
}

Example 3: C Program to Illustrate Indirect Recursion

This C program illustrates the concept of indirect recursion. Two functions, functionA() and functionB(), call each other indirectly.

// C Program to Illustrate the Indirect Recursion


#include <stdio.h>

void functionA(int n)
{
if (n < 1) {
return;
}
printf("%d ", n);
n = n - 1;

// Indirect recursive call to functionB


functionB(n);
}
CHAPTER 4. C FUNCTIONS 127

void functionB(int n)
{
if (n < 2) {
return;
}

printf("%d ", n);


n = n / 2;

// Indirect recursive call to functionA


functionA(n);
}

int main()
{
// Function call
functionB(20);

return 0;
}

Output:
20 10 9 4 3 1

4.8.7 Applications of Recursion in C

Recursion is widely used to solve various problems, from simple tasks like printing linked lists to complex problems in fields such as Artificial Intelligence.
Some common applications include:

• Tree-Graph Algorithms

• Mathematical Problems

• Divide and Conquer

• Dynamic Programming

• Postfix to Infix Conversion

• Searching and Sorting Algorithms

4.8.8 Advantages of C Recursion

Using recursion in C offers several advantages:

• Recursion can effectively reduce the length of the code.

• Some problems, like the Tower of Hanoi and tree traversals, are more easily solved with recursion.

• Data structures like linked lists and trees are recursive by nature, so recursive methods are easier to implement for these data structures.

4.8.9 Disadvantages of C Recursion

However, recursion also comes with certain limitations:

• Recursive functions may make the program slower due to the overhead of function calls.

• Recursive functions consume extra space in the function call stack because of separate stack frames.

• Recursive methods can be more difficult to understand and implement.


CHAPTER 4. C FUNCTIONS 128

4.9 Pointers in C

A pointer is a variable that holds the address of another variable of the same datatype. A pointer variable contains the address of another variable,
which is a location in memory. The value of the pointer variable is stored in another memory location.

A pointer is a variable that stores the memory address of another variable. Instead of holding a direct value, it holds the address where the value is
stored in memory. There are two important operators used in pointer concepts:

• Dereferencing operator (*): Used to declare a pointer variable and access the value stored at the address.

• Address operator (&): Used to return the address of a variable or to assign the address of a variable to a pointer.

For example:

int a = 100;
int *pt = &a;

Here, pt is a pointer, and it can hold the address of variable a. The & symbol is called the reference operator.

Example 1

#include <stdio.h>

int main() {
int m = 100; // integer variable
int *ptr = &m; // pointer variable storing address of m

printf("The Value of Variable m is: %d\n", m);


printf("The Memory Address of Variable m is: %p\n", &m);
printf("The Memory Address of Variable m using ptr: %p\n", ptr);

return 0;
}

Output:

The Value of Variable m is: 100


The Memory Address of Variable m is: 0x7ffee1eea79c
The Memory Address of Variable m using ptr: 0x7ffee1eea79c

Important Points:

• %p format specifier is used to print the address stored in pointer variables.

• Printing a pointer with %d format specifier may result in a warning or undefined behavior.

• The memory address format is always in hexadecimal format (starting with 0x).

• Pointers are essential for dynamic memory allocation.

Example 2

#include <stdio.h>

int main() {
int a = 10; // integer variable
int *ptr; // pointer declaration
ptr = &a; // pointer initialization

printf("ptr = %p\n", ptr);


CHAPTER 4. C FUNCTIONS 129

printf("*ptr = %d", *ptr); // dereferencing

return 0;
}

Output:

ptr = 0x7fffa0757dd4
*ptr = 10

Key Points to Remember About Pointers in C

• Normal variables store values, whereas pointer variables store the addresses of variables.

• The content of a pointer is always a whole number (i.e., an address).

• A C pointer is initialized to NULL, e.g., int *p = NULL;.

• The value of a null pointer is zero.

• & is used to get the address of a variable.

• * is used to get the value of the variable that the pointer points to.

• If a pointer in C is assigned NULL, it means it points to nothing.

Pointer Operations

A. Pointer Declaration

To declare a pointer, use the (*) dereference operator before its name. In pointer declaration, the pointer is declared but not initialized.

B. Pointer Initialization

Pointer initialization involves assigning an initial value to the pointer variable using the (&) address operator.

C. Pointer Dereferencing

Dereferencing a pointer accesses the value stored at the memory address specified by the pointer.

Note: Always initialize pointers before use to avoid errors.

Example 3: String as Pointer

#include <stdio.h>

int main() {
char *s = "santhosh"; // string as pointer
printf("%s", s);
return 0;
}

Output:

santhosh
CHAPTER 4. C FUNCTIONS 130

Types of Pointers in C

Pointers can be classified into various types:

1. Integer Pointers: Point to integer values.

2. Array Pointers: Point to arrays.

3. Structure Pointers: Point to structures.

4. Function Pointers: Point to functions.

5. Double Pointers: Point to another pointer.

6. NULL Pointers: Do not point to any memory location.

7. Void Pointers: Generic pointers without associated data types.

8. Wild Pointers: Uninitialized pointers.

9. Constant Pointers: Memory address stored is constant.

10. Pointer to Constant: Point to constant values.

Advantages of Pointers

• Enables access to a variable defined outside the function.

• Can be used to pass information between a function and its reference point.

• More efficient in handling data tables.

• Reduces the length and complexity of a program.

• Sometimes increases execution speed.

• Enable dynamic memory allocation and deallocation.

• Efficiently access arrays and structures.

• Reduce program length and execution time.

• Facilitate the implementation of data structures like linked lists and trees.

Disadvantages of Pointers

• Can cause memory corruption if misused.

• Lead to memory leaks if not managed properly.

• Comparatively slower than variables.

• Uninitialized pointers may cause segmentation faults.

Declaration of a Pointer Variable

General Syntax:

data_type *pointer_name;

• The asterisk (*) indicates that pointern ameisapointervariable. Example:


• int *ptr;

Here, ptr is not an integer variable but a pointer to an integer variable.


CHAPTER 4. C FUNCTIONS 131

Dereference Operator (*):

The unary operator * is the dereferencing operator or indirection operator. When applied to a pointer, it accesses the value the pointer points to.
Example:

#include <stdio.h>
void main() {
int a = 50;
int *ptr;
ptr = &a;
printf("Value of a: %d", a); // 50
printf("Address of a: %p", ptr); // Address of a
printf("Value at ptr: %d", *ptr); // 50
}

The Null Pointer

A null pointer is a pointer that does not point to any valid memory address. It can be initialized as:

int *ptr = NULL;

This indicates that the pointer does not point to any valid reference.

The NULL pointer is a pointer that does not point to any location but NULL. According to the C11 standard:

“An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null
pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to
any object or function.”

Syntax of NULL Pointer Declaration in C

type pointer_name = NULL;


type pointer_name = 0;

NULL expands to an implementation-defined null pointer constant defined in header files like stdio.h, stddef.h, and stdlib.h.

Uses of NULL Pointer in C

• To initialize a pointer variable when it hasn’t been assigned a valid memory address.

• To check for a null pointer before accessing any pointer variable, enabling error handling.

• To pass a null pointer to a function argument when no valid memory address is needed.

• In data structures like trees and linked lists, to indicate the end.

Check if the Pointer is NULL

The pointer can be checked for NULL using the equality operator (==):

ptr == NULL;

This evaluates to true if the pointer is NULL.

Examples of NULL Pointer in C

Example 1: Avoid Segmentation Fault with NULL Pointer

// C NULL pointer demonstration


#include <stdio.h>
CHAPTER 4. C FUNCTIONS 132

int main()
{
// declaring null pointer
int* ptr = NULL;

// dereferencing only if the pointer has a value


if (ptr == NULL) {
printf("Pointer does not point to anything");
} else {
printf("Value pointed by pointer: %d", *ptr);
}
return 0;
}

Output: Pointer does not point to anything

Example 2: Check Memory Allocation with malloc()

// C Program to use NULL pointer to check for malloc error


#include <stdio.h>
#include <stdlib.h>

int main()
{
// declaring dynamic memory for ptr
int* ptr = (int*)malloc(5 * sizeof(int));

// checking if memory allocation is successful


if (!ptr) {
printf("Memory Allocation Failed");
exit(0);
}

return 0;
}

Example 3: Dereferencing a NULL Pointer

// Dereferencing a null pointer


#include <stdio.h>
int main()
{
int *ptr = NULL;
printf("%d", *ptr); // May crash depending on system behavior
return 0;
}

Dereferencing a NULL pointer can cause undefined behavior and may crash.

Example 4: Passing NULL to a Function

// C Program to illustrate how passing NULL works


#include <stdio.h>

void foo(int* string)


{
if (string == NULL) {
printf("NULL Pointer Passed");
CHAPTER 4. C FUNCTIONS 133

return;
}
printf("Non-Null Pointer Passed");
}

int main()
{
foo(NULL); // Passing NULL
return 0;
}

Output: NULL Pointer Passed

Difference Between NULL Pointer and Void Pointer in C

NULL Pointer Void Pointer


Does not point to anything. It is a special reserved value for pointers. Points to a memory location that may contain typeless data.
Any pointer type can be assigned NULL. Can only be of type void.
All NULL pointers are equal. Void pointers can be different.
NULL Pointer is a value. Void Pointer is a type.
Example: int *ptr = NULL; Example: void *ptr;

Pointer Initialization

Pointer initialization assigns the address of a variable to a pointer variable. The & operator is used to determine the address of a variable. Example:

int x = 5;
int *ptr = &x;

Pointer Arithmetic in C

Pointer arithmetic is the set of valid arithmetic operations that can be performed on pointers. Pointer variables store the memory address of another
variable and do not store any value themselves. As a result, only a few operations are allowed on pointers in C. These operations differ from standard
arithmetic and include:

1. Increment/Decrement of a Pointer

2. Addition of an integer to/from a pointer

3. Subtraction of an integer to/from a pointer

4. Subtraction of two pointers of the same type

5. Comparison of pointers/Comparing two pointers.

4.10 Increment/Decrement of a Pointer

When a pointer is incremented or decremented, the address it stores changes by a value equal to the size of the data type it points to. For example:

• If an int pointer storing the address 1000 is incremented, the new address will be 1004 (size of int is 4 bytes).

• If a float pointer storing the address 1000 is incremented, the new address will also be 1004 (size of float is 4 bytes).

• If a char pointer storing the address 1000 is incremented, the new address will be 1001 (size of char is 1 byte).
CHAPTER 4. C FUNCTIONS 134

Example: Increment/Decrement of Pointers

#include <stdio.h>

int main() {
int a = 22;
int *p = &a;
printf("p = %p\n", p);
p++;
printf("p++ = %p\n", p);
p--;
printf("p-- = %p\n", p);

float b = 22.22;
float *q = &b;
printf("q = %p\n", q);
q++;
printf("q++ = %p\n", q);
q--;
printf("q-- = %p\n", q);

char c = ’a’;
char *r = &c;
printf("r = %p\n", r);
r++;
printf("r++ = %p\n", r);
r--;
printf("r-- = %p\n", r);

return 0;
}

4.11 Addition of an Integer to a Pointer

Adding an integer to a pointer adjusts the address it stores by a value equal to the integer multiplied by the size of the data type.
CHAPTER 4. C FUNCTIONS 135

Example: Addition of Integer to a Pointer

#include <stdio.h>

int main() {
int N = 4;
int *ptr = &N;

printf("Pointer before addition: %p\n", ptr);


ptr = ptr + 3;
printf("Pointer after addition: %p\n", ptr);

return 0;
}

4.12 Subtraction of an Integer from a Pointer

Similar to addition, subtracting an integer adjusts the pointer address by the integer multiplied by the size of the data type.

Example: Subtraction of Integer from a Pointer

#include <stdio.h>

int main() {
int N = 4;
int *ptr = &N;

printf("Pointer before subtraction: %p\n", ptr);


ptr = ptr - 3;
printf("Pointer after subtraction: %p\n", ptr);

return 0;
}

4.13 Subtraction of Two Pointers

Subtracting two pointers of the same type calculates the difference in the number of elements between them. The result is the number of increments of
the pointer type.

Example: Subtraction of Two Pointers

#include <stdio.h>

int main() {
int x = 6, N = 4;
int *ptr1 = &N, *ptr2 = &x;
CHAPTER 4. C FUNCTIONS 136

printf("ptr1 = %p, ptr2 = %p\n", ptr1, ptr2);


int diff = ptr1 - ptr2;
printf("Difference = %d\n", diff);

return 0;
}

4.14 Comparison of Pointers

Pointers can be compared using relational operators (<, <=, >, >=, ==, !=). Comparison checks whether the addresses stored in the pointers satisfy
the condition.

Example: Pointer Comparison

#include <stdio.h>

int main() {
int arr[5];
int *ptr1 = arr;
int *ptr2 = &arr[3];

if (ptr1 < ptr2) {


printf("ptr1 points to a lower memory address than ptr2\n");
}

return 0;
}

Example:

int a = 10;
int *ptr = &a;
ptr = ptr + 1; // Moves to the next memory location based on data type size.

Applications of Pointers in C

Pointers in C are variables that are used to store the memory address of another variable. Pointers allow us to efficiently manage the memory and hence
optimize our program. Below are some major applications of pointers in C.

Prerequisite

Familiarity with the basics of pointers in C is required.

4.15 Major Applications of Pointers

4.15.1 1. Passing Arguments by Reference

Passing arguments by reference serves two purposes:

• To modify the variable in another function.

• For efficiency purposes.

Example 1: Swapping Two Numbers

The following example demonstrates the use of pointers by swapping two numbers:
CHAPTER 4. C FUNCTIONS 137

#include <stdio.h>

void swap(int* x, int* y) {


int temp = *x;
*x = *y;
*y = temp;
}

int main() {
int x = 10, y = 20;
swap(&x, &y);
printf("%d %d\n", x, y);
return 0;
}

Output: 20 10

Example 2: Printing an Array by Reference

The following example demonstrates the use of pointers to write efficient code:

#include <stdio.h>

void printArray(int* arr, int n) {


for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
}

int main() {
int arr[5] = {1, 2, 3, 4, 5};
printArray(arr, 5);
return 0;
}

Output: 1 2 3 4 5

Note: Passing a large structure without reference creates a copy of the structure, leading to memory inefficiency.

4.15.2 2. Accessing Array Elements

Pointers can be used to access and modify elements of an array. The compiler internally uses pointer arithmetic to access array elements.

Example: Accessing Array Elements with Pointers

#include <stdio.h>

int main() {
int arr[] = {100, 200, 300, 400};
printf("%d ", arr[2]); // Access using index
printf("%d\n", *(arr + 2)); // Access using pointers
return 0;
}

Output: 300 300

4.15.3 3. Returning Multiple Values

In C, functions can only return a single value. Using pointers, multiple values can be returned from a function.
CHAPTER 4. C FUNCTIONS 138

Example: Returning Square and Square Root

#include <math.h>
#include <stdio.h>

void fun(int n, int* square, double* sq_root) {


*square = n * n;
*sq_root = sqrt(n);
}

int main() {
int n = 100;
int sq;
double sq_root;
fun(n, &sq, &sq_root);
printf("%d %f\n", sq, sq_root);
return 0;
}

Output:

10000
10.000000

4.15.4 4. Dynamic Memory Allocation

Pointers enable dynamic memory allocation, allowing memory to be allocated at runtime and freed explicitly when no longer needed.

Example: Dynamic Array Allocation

#include <stdio.h>
#include <stdlib.h>

int* createArr(int n) {
int* arr = (int*) malloc(n * sizeof(int));
return arr;
}

int main() {
int* pt = createArr(10);
free(pt); // Free the allocated memory
return 0;
}

4.16 Pointers and Functions

Pointers are often passed to functions to allow access and modification of data.

Call by Value

In call by value, the values of actual parameters are copied into formal parameters. Changes to formal parameters do not affect the actual parameters.
Example:

void swap(int x, int y) {


int temp = x;
x = y;
y = temp;
}
CHAPTER 4. C FUNCTIONS 139

Call by Reference

In call by reference, the addresses of actual parameters are passed. Changes to formal parameters affect the actual parameters. Example:

void swap(int *x, int *y) {


int temp = *x;
*x = *y;
*y = temp;
}

Difference between Call by Value and Call by Reference

Call by Value

• When a function is called, the values of variables are passed.

• The type of formal parameters should be the same as the type of actual parameters.

• Formal parameters contain the values of actual parameters.

Call by Address (Reference)

• When a function is called, the address of variables is passed.

• The type of formal parameters should be the same as the type of actual parameters, but they have to be declared as pointers.

• Formal parameters contain the addresses of actual parameters.

Differences Between Actual and Formal Parameters

Actual Parameters

• Actual parameters are also called the argument list. Example: add(m, n)

• The variables used in the function call are called actual parameters.

• Actual parameters are used in the calling function when a function is invoked.

• Example:

add(m, n)

Here, m and n are called actual parameters.

• Actual parameters send data to the formal parameters.

Formal Parameters

• Formal parameters are also called dummy parameters. Example: int add(int a, int b)

• The variables defined in the function header are called formal parameters.

• Formal parameters are used in the function header of the called function.

• Example:

int add(int a, int b) {


// function body
}

Here, a and b are called formal parameters.

• Formal parameters receive data from the actual parameters.


CHAPTER 4. C FUNCTIONS 140

Passing Pointers and Function Pointers in C

1. Arguments Passing Without Pointer

When arguments are passed without pointers, changes made in the function affect only the local variables. Here’s an example:

#include <stdio.h>

void swap(int a, int b) {


int temp = a;
a = b;
b = temp;
}

int main() {
int a = 10, b = 20;
swap(a, b);
printf("Values after swap function are: %d, %d", a, b);
return 0;
}

Output:

Values after swap function are: 10, 20

2. Arguments Passing With Pointers

Passing pointers allows the function to directly modify the variables’ values stored at their memory addresses.

#include <stdio.h>

void swap(int* a, int* b) {


int temp = *a;
*a = *b;
*b = temp;
}

int main() {
int a = 10, b = 20;
printf("Values before swap function are: %d, %d\n", a, b);
swap(&a, &b);
printf("Values after swap function are: %d, %d", a, b);
return 0;
}

Output:

Values before swap function are: 10, 20


Values after swap function are: 20, 10

3.1 Basic Usage

Function pointers allow dynamic function calls, making the code more modular.

#include <stdio.h>

void fun(int a) {
printf("Value of a is %d\n", a);
}
CHAPTER 4. C FUNCTIONS 141

int main() {
void (*fun_ptr)(int) = &fun; // Declare and initialize function pointer
(*fun_ptr)(10); // Call function via pointer
return 0;
}

Output:

Value of a is 10

3.2 Simplified Syntax

The & and * operators can be omitted in some cases for function pointers.

#include <stdio.h>

void fun(int a) {
printf("Value of a is %d\n", a);
}

int main() {
void (*fun_ptr)(int) = fun; // Simplified assignment
fun_ptr(10); // Simplified call
return 0;
}

Output:

Value of a is 10

3.3 Array of Function Pointers

Function pointers can be organized in arrays to simplify switch-case logic.

#include <stdio.h>

void add(int a, int b) { printf("Addition is %d\n", a + b); }


void sub(int a, int b) { printf("Subtraction is %d\n", a - b); }
void mul(int a, int b) { printf("Multiplication is %d\n", a * b); }

int main() {
void (*fptrArr[])(int, int) = { add, sub, mul };
int ch, a = 15, b = 10;

printf("Enter Choice: 0 for add, 1 for subtract, 2 for multiply\n");


scanf("%d", &ch);

if (ch < 3) (*fptrArr[ch])(a, b);


return 0;
}

Output Example:

Enter Choice: 0 for add, 1 for subtract, 2 for multiply


2
Multiplication is 150
CHAPTER 4. C FUNCTIONS 142

3.4 Passing Function Pointers as Arguments

Function pointers can be passed to other functions to increase flexibility.

#include <stdio.h>

void fun1() { printf("Fun1\n"); }


void fun2() { printf("Fun2\n"); }

void wrapper(void (*fun)()) { fun(); }

int main() {
wrapper(fun1);
wrapper(fun2);
return 0;
}

Output:

Fun1
Fun2

3.5 Application in qsort()

The standard library function qsort() uses function pointers for custom comparisons.

#include <stdio.h>
#include <stdlib.h>

int comp(const void* a, const void* b) {


return (*(int*)a - *(int*)b);
}

int main() {
int arr[] = { 10, 5, 15, 12, 90, 80 };
int n = sizeof(arr) / sizeof(arr[0]);

qsort(arr, n, sizeof(int), comp); // Sort using qsort and comp

for (int i = 0; i < n; i++)


printf("%d ", arr[i]);
return 0;
}

Output:

5 10 12 15 80 90

4. General Notes on Function Pointers

• Function pointers point to executable code, not data.

• No memory allocation is required for function pointers.

• Function names can directly serve as pointers.

4.17 Dynamic Memory Allocation in C

Dynamic memory allocation in C provides methods to allocate memory at runtime. This is essential when the size of the data structure is not known at
compile time. The functions malloc(), calloc(), free(), and realloc() are part of the standard library stdlib.h.
CHAPTER 4. C FUNCTIONS 143

Functions

• malloc(): Allocates a block of memory of specified size (in bytes) and returns a pointer to the beginning.

• calloc(): Allocates memory for an array of elements, initializes them to zero, and returns a pointer.

• free(): Deallocates previously allocated memory.

• realloc(): Changes the size of previously allocated memory block.

Examples

1. Using malloc()

#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr;
int n = 5;

ptr = (int *)malloc(n * sizeof(int));


if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}

for (int i = 0; i < n; i++) {


ptr[i] = i + 1;
}

printf("Array elements: ");


for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
}

free(ptr);
return 0;
}

2. Using calloc()

#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr;
int n = 5;

ptr = (int *)calloc(n, sizeof(int));


if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}

printf("Array elements initialized to zero: ");


for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
CHAPTER 4. C FUNCTIONS 144

free(ptr);
return 0;
}

3. Using realloc()

#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr;
int n = 5;

ptr = (int *)malloc(n * sizeof(int));


if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}

for (int i = 0; i < n; i++) {


ptr[i] = i + 1;
}

n = 10;
ptr = (int *)realloc(ptr, n * sizeof(int));
if (ptr == NULL) {
printf("Memory reallocation failed\n");
return 1;
}

for (int i = 5; i < n; i++) {


ptr[i] = i + 1;
}

printf("Extended array elements: ");


for (int i = 0; i < n; i++) {
printf("%d ", ptr[i]);
}

free(ptr);
return 0;
}

4. Using free()

#include <stdio.h>
#include <stdlib.h>

int main() {
int *ptr;
int n = 5;

ptr = (int *)malloc(n * sizeof(int));


if (ptr == NULL) {
printf("Memory allocation failed\n");
CHAPTER 4. C FUNCTIONS 145

return 1;
}

for (int i = 0; i < n; i++) {


ptr[i] = i + 1;
}

free(ptr);

printf("Memory has been freed.\n");


return 0;
}

Conclusion

Dynamic memory allocation is a powerful feature in C that allows efficient use of memory. Proper usage of free() ensures there are no memory leaks,
making programs robust and efficient.

You might also like