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

Understanding Recursive Functions in C

The document provides an overview of recursive functions, function prototypes, the structure of a C program, pointers, and structures in C programming. It explains the concept of recursion with examples such as calculating factorial and reversing a string, and details the structure of a C program including documentation, preprocessor directives, and user-defined functions. Additionally, it covers pointers, their declaration, initialization, and usage, as well as the definition and manipulation of structures.

Uploaded by

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

Understanding Recursive Functions in C

The document provides an overview of recursive functions, function prototypes, the structure of a C program, pointers, and structures in C programming. It explains the concept of recursion with examples such as calculating factorial and reversing a string, and details the structure of a C program including documentation, preprocessor directives, and user-defined functions. Additionally, it covers pointers, their declaration, initialization, and usage, as well as the definition and manipulation of structures.

Uploaded by

bikersgang5hots
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Recursive function :

A recursive function is a function that calls itself either directly or indirectly in order
to solve a problem. It breaks down a problem into smaller subproblems of the same
type and solves each subproblem recursively until a base case is reached, which is a
problem small enough to solve directly without further recursion. Recursive
functions are commonly used in programming when a problem can be naturally
decomposed into simpler instances of the same problem.

Here's an example of a recursive function to calculate the factorial of a non-


negative integer:

#include <stdio.h>

// Recursive function to calculate factorial

Int factorial(int n) {

// Base case: if n is 0 or 1, factorial is 1

If (n == 0 || n == 1) {

Return 1;

} else {

// Recursive call to factorial function

Return n * factorial(n – 1);

Int main() {

Int num = 5;

Printf(“Factorial of %d is %d\n”, num, factorial(num));

Return 0;

```

Explanation:

- The `factorial` function calculates the factorial of a non-negative integer `n`.

- The base case is when `n` is 0 or 1, in which case the factorial is 1.

- If `n` is greater than 1, the function recursively calls itself with `n-1` until the base
case is reached.
- The result is calculated by multiplying `n` with the factorial of `n-1`.

Now, let’s look at an example of a recursive function that reverses a string:

```c

#include <stdio.h>

#include <string.h>

// Recursive function to reverse a string

Void reverseString(char str[], int start, int end) {

If (start >= end) {

Return;

// Swap characters at start and end positions

Char temp = str[start];

Str[start] = str[end];

Str[end] = temp;

// Recursive call to reverseString function

reverseString(str, start + 1, end – 1);

Int main() {

Char str[] = “Hello, World!”;

Printf(“Original string: %s\n”, str);

reverseString(str, 0, strlen(str) – 1);

printf(“Reversed string: %s\n”, str);

return 0;

```
Explanation:

- The `reverseString` function takes a string `str`, and two indices `start` and
`end`.

- If `start` is greater than or equal to `end`, it means the entire string has been
reversed, so the function returns.

- Otherwise, it swaps the characters at positions `start` and `end`, and recursively
calls itself with `start + 1` and `end – 1`.

- This process continues until the base case is reached, effectively reversing the
string in place.

Recursive functions are powerful and elegant solutions for problems that exhibit
self-similar substructures, but they should be used judiciously to avoid stack
overflow errors and inefficient execution.
Function prototype :

Sure! In C programming, a function prototype is a declaration that specifies the


function’s name, return type, and parameters without providing the function’s
actual implementation. It serves as a forward declaration that tells the compiler
about the existence of the function and its interface. Function prototypes are
typically placed at the beginning of a program or in header files to allow other parts
of the program to call the function before its actual implementation is encountered.

Here’s an example to illustrate:

```c

#include <stdio.h>

// Function prototype

Int add(int num1, int num2);

Int main() {

Int result;

// Calling the add function

Result = add(5, 3);

Printf(“Result: %d\n”, result);

Return 0;

// Function definition

Int add(int num1, int num2) {

Return num1 + num2;

```

In this example:

- The function prototype `int add(int num1, int num2);` declares the `add` function
with a return type of `int` and two parameters of type `int`.

- The `main` function calls the `add` function before its actual implementation is
encountered.

- The function definition `int add(int num1, int num2)` provides the actual
implementation of the `add` function.
By providing a function prototype, the compiler knows how to handle calls to the
`add` function even before it encounters the actual definition. This helps in
organizing code, promoting modularity, and catching errors related to function calls
and parameters early in the compilation process.

Structure of c program:
A C program typically follows a well-defined structure consisting of various
components that work together to perform specific tasks. Here is a
detailed explanation of the structure of a C program:

### 1. Documentation Section

This section includes comments that describe the purpose of the program,
the author, date of creation, and other relevant information. Comments
can be single-line (using `//`) or multi-line (using `/* … */`).

```c

/*

Program: Simple Example

Author: John Doe

Date: May 19, 2024

Description: This program demonstrates the structure of a C program.

*/

```

### 2. Preprocessor Directives

These are instructions to the preprocessor, which processes the source


code before compilation. Common directives include `#include` for
including header files and `#define` for defining macros.

```c

#include <stdio.h> // Standard input-output library

#define PI 3.14 // Defining a constant

```

### 3. Global Declarations

Variables and functions that need to be accessed from multiple functions


in the program are declared here.

```c

Int globalVariable = 0; // Global variable declaration

```
### 4. Function Prototypes

These are declarations of functions that will be defined later in the


program. They inform the compiler about the function’s name, return
type, and parameters.

```c

Void greet(void); // Function prototype for a function that returns void


and takes no arguments

Int add(int, int); // Function prototype for a function that returns an int
and takes two int arguments

```

### 5. Main() Function

This is the entry point of every C program. The `main` function is where
execution starts. It can return an integer value and can optionally take
command-line arguments.

```c

Int main() {

// Variable declarations

Int a = 5, b = 10;

// Function calls

Greet();

Int result = add(a, b);

// Output result

Printf(“The sum of %d and %d is %d\n”, a, b, result);

Return 0; // Indicating successful completion

```

### 6. User-Defined Functions

These are additional functions defined by the programmer to perform


specific tasks. Defining functions outside the `main` function helps in
modularizing the code and improving readability.

```c
Void greet(void) {

Printf(“Hello, welcome to the C program structure demonstration!\n”);

Int add(int x, int y) {

Return x + y;

```

### Example of a Complete C Program

```c

/*

Program: Simple Example

Author: John Doe

Date: May 19, 2024

Description: This program demonstrates the structure of a C program.

*/

#include <stdio.h> // Standard input-output library

#define PI 3.14 // Defining a constant

Int globalVariable = 0; // Global variable declaration

Void greet(void); // Function prototype for greet

Int add(int, int); // Function prototype for add

Int main() {

// Variable declarations

Int a = 5, b = 10;

// Function calls

Greet();

Int result = add(a, b);


// Output result

Printf(“The sum of %d and %d is %d\n”, a, b, result);

Return 0; // Indicating successful completion

Void greet(void) {

Printf(“Hello, welcome to the C program structure demonstration!\n”);

Int add(int x, int y) {

Return x + y;

```

### Explanation of the Example Program

- **Documentation Section**: The comments at the beginning provide


metadata about the program.

- **Preprocessor Directives**: `#include <stdio.h>` includes the standard


I/O library, and `#define PI 3.14` defines a macro for π.

- **Global Declarations**: `int globalVariable` is a global variable


accessible throughout the program.

- **Function Prototypes**: `void greet(void)` and `int add(int, int)` are


prototypes for functions defined later.

- **main() Function**: The program execution starts here. It declares local


variables `a` and `b`, calls `greet` and `add`, and prints the result.

- **User-Defined Functions**: `greet` prints a welcome message, and `add`


returns the sum of two integers.

This structured approach ensures clarity, maintainability, and reusability


of the code.
Pointers :

Pointers are a fundamental and powerful feature in C programming, providing the


ability to directly manipulate memory addresses. Understanding pointers is crucial
for efficient and effective C programming. Below is a detailed explanation of
pointers, including their syntax, usage, and examples.

### What is a Pointer?

A pointer is a variable that stores the memory address of another variable. Instead
of holding a data value directly, a pointer holds the address where the data is
stored. This allows for indirect access and manipulation of variables.

### Declaring Pointers

To declare a pointer, you use the asterisk (`*`) symbol. The syntax for declaring a
pointer is:

```c

Type *pointerName;

```

For example:

```c

Int *p; // Pointer to an integer

Char *c; // Pointer to a character

```

### Pointer Initialization

Pointers are typically initialized with the address of a variable using the address-of
operator (`&`):

```c

Int a = 10;

Int *p = &a; // p now holds the address of a

```

### Dereferencing Pointers


Dereferencing a pointer means accessing the value stored at the memory address
the pointer is pointing to. This is done using the asterisk (`*`) operator:

```c

Int value = *p; // value now holds the integer stored at the address p points to

```

### Example Program

Here is a complete example demonstrating the use of pointers in a C program:

```c

#include <stdio.h>

Int main() {

Int a = 10; // Declare an integer variable

Int *p = &a; // Declare a pointer and initialize it with the address of a

Printf(“Address of a: %p\n”, (void*)&a); // Print the address of a

Printf(“Value of p (address of a): %p\n”, (void*)p); // Print the value of p (which is


the address of a)

Printf(“Value of a: %d\n”, a); // Print the value of a

Printf(“Value pointed to by p: %d\n”, *p); // Print the value pointed to by p (which


is the value of a)

*p = 20; // Modify the value of a using the pointer

Printf(“New value of a after modification: %d\n”, a); // Print the new value of a

Return 0;

```

### Explanation of the Example

- **Declaration and Initialization**:

- `int a = 10;` declares an integer variable `a` and initializes it to 10.

- `int *p = &a;` declares a pointer `p` and initializes it with the address of `a`
using the address-of operator `&`.

- **Printing Addresses and Values**:


- `printf(“Address of a: %p\n”, (void*)&a);` prints the address of `a`. The `%p`
format specifier is used for printing addresses. `(void*)` is a type cast to ensure the
address is correctly interpreted.

- `printf(“Value of p (address of a): %p\n”, (void*)p);` prints the value stored in


`p`, which is the address of `a`.

- `printf(“Value of a: %d\n”, a);` prints the value of `a`.

- `printf(“Value pointed to by p: %d\n”, *p);` prints the value at the address stored
in `p`, which is the value of `a`.

- **Modifying the Value Using the Pointer**:

- `*p = 20;` changes the value at the address stored in `p` (which is `a`) to 20.

- `printf(“New value of a after modification: %d\n”, a);` prints the new value of `a`
to show that it has been updated via the pointer.

### Key Concepts

1. **Pointer Arithmetic**: Pointers can be incremented or decremented to


traverse arrays or data structures. For example, if `p` is a pointer to an
integer, `p++` will point to the next integer in memory.
2. **NULL Pointer**: A special pointer value (`NULL`) is used to indicate that the
pointer does not point to any valid memory location.

```c

Int *ptr = NULL; // A pointer that points to nothing

```

3. **Pointers to Pointers**: You can have pointers that point to other pointers,
which is useful for dynamic memory allocation and multi-level data
structures.

```c

Int **pp = &p; // Pointer to a pointer

```

4. **Dynamic Memory Allocation**: Pointers are crucial for dynamic memory


allocation using functions like `malloc`, `calloc`, and `free` from the
`<stdlib.h>` library.

```c
Int *arr = (int*)malloc(5 * sizeof(int)); // Allocate memory for an array of 5
integers

```

Understanding pointers is essential for tasks like dynamic memory management,


passing arguments by reference to functions, and working with complex data
structures such as linked lists, trees, and graphs.

Structure:

Structures in C are user-defined data types that allow grouping of variables of


different types under a single name. This is particularly useful for modeling complex
data types. Here is a detailed explanation of declaring, initializing, and accessing
structures in a C program:

### Declaring a Structure

A structure is defined using the `struct` keyword, followed by the structure name
and the body of the structure enclosed in curly braces. The body contains the
members (variables) of different types.

```c

Struct Person {

Char name[50];

Int age;

Float height;

};

```

In this example, `Person` is a structure type that contains three members: `name`,
`age`, and `height`.

### Creating Structure Variables

Once a structure is defined, you can create variables of that type using the
structure name.

```c

Struct Person person1, person2;

```

Alternatively, you can define the structure and declare the variables in one step.
```c

Struct Person {

Char name[50];

Int age;

Float height;

} person1, person2;

```

### Initializing Structure Variables

You can initialize structure variables at the time of declaration using an initializer
list.

```c

Struct Person person1 = {“Alice”, 30, 5.5};

```

Alternatively, you can initialize the members individually after the variable has been
declared.

```c

Struct Person person2;

[Link] = 25;

[Link] = 5.7;

Strcpy([Link], “Bob”); // For string assignment, use strcpy from <string.h>

```

### Accessing Structure Members

You can access the members of a structure using the dot operator (`.`).

```c

Printf(“Name: %s\n”, [Link]);

Printf(“Age: %d\n”, [Link]);

Printf(“Height: %.1f\n”, [Link]);

```
### Example Program

Here is a complete example demonstrating structure declaration, initialization, and


member access in a C program:

```c

#include <stdio.h>

#include <string.h>

// Structure declaration

Struct Person {

Char name[50];

Int age;

Float height;

};

Int main() {

// Structure variable declaration and initialization

Struct Person person1 = {“Alice”, 30, 5.5};

Struct Person person2;

// Initializing members individually

[Link] = 25;

[Link] = 5.7;

Strcpy([Link], “Bob”); // For string assignment, use strcpy from


<string.h>

// Accessing and printing structure members

Printf(“Person 1:\n”);

Printf(“Name: %s\n”, [Link]);

Printf(“Age: %d\n”, [Link]);

Printf(“Height: %.1f\n”, [Link]);

Printf(“Person 2:\n”);

Printf(“Name: %s\n”, [Link]);

Printf(“Age: %d\n”, [Link]);


Printf(“Height: %.1f\n”, [Link]);

Return 0;

```

### Explanation of the Example

1. **Structure Declaration**:

- The `struct Person` declaration defines a structure with three members: `name`
(a character array), `age` (an integer), and `height` (a floating-point number).

2. **Variable Declaration and Initialization**:

- `struct Person person1 = {“Alice”, 30, 5.5};` initializes `person1` with values
for `name`, `age`, and `height`.

- `struct Person person2;` declares `person2` without initial values.

- `[Link] = 25;`, `[Link] = 5.7;`, and `strcpy([Link],


“Bob”);` individually initialize the members of `person2`.

3. **Accessing Members**:

- The `printf` statements use the dot operator to access and print the values of
the structure members for `person1` and `person2`.

### Additional Concepts

1. **Nested Structures**:

- Structures can contain other structures as members, allowing for complex data
types.

```c

Struct Date {

Int day;

Int month;

Int year;

};

Struct Employee {

Char name[50];
Struct Date joiningDate;

Float salary;

};

```

2. **Pointers to Structures**:

- You can use pointers to structures to dynamically allocate memory and access
structure members using the arrow operator (`->`).

```c

Struct Person *pPerson;

pPerson = &person1;

printf(“Name: %s\n”, pPerson->name); // Using arrow operator to access


members

```

3. **Typedef for Structures**:

- The `typedef` keyword simplifies the syntax by allowing you to define an alias
for the structure type.

```c

Typedef struct {

Char name[50];

Int age;

Float height;

} Person;

Person person3; // Now you can use ‘Person’ instead of ‘struct Person’

```

Understanding structures is crucial for organizing and managing complex data in C


programs, making code more readable and maintainable.
Self Refrencial:

Self-referential structures are structures that contain a member which is a pointer to


the same type of structure. This concept is fundamental for creating complex data
structures such as linked lists, trees, and graphs. Here is a detailed explanation of
self-referential structures in C, including an example of their use in a linked list.

### Declaring a Self-Referential Structure

To declare a self-referential structure, you include a pointer to the structure type


within its definition. Here is a basic example:

```c

Struct Node {

Int data;

Struct Node *next;

};

```

In this example:

- `struct Node` is a structure that represents a node in a linked list.

- `data` is an integer that stores the data for the node.

- `next` is a pointer to another `struct Node`, allowing the creation of a chain of


nodes.

### Example: Implementing a Simple Linked List

Let’s create a simple linked list that can store integers. The program will include
functions to add nodes and print the list.

#### Complete Program

```c
#include <stdio.h>

#include <stdlib.h>

// Define the self-referential structure

Struct Node {

Int data;

Struct Node *next;

};

// Function to create a new node

Struct Node* createNode(int data) {

Struct Node *newNode = (struct Node*)malloc(sizeof(struct Node));

newNode->data = data;

newNode->next = NULL;

return newNode;

// Function to add a node at the end of the list

Void appendNode(struct Node **head, int data) {

Struct Node *newNode = createNode(data);

If (*head == NULL) {

*head = newNode;

} else {

Struct Node *temp = *head;

While (temp->next != NULL) {

Temp = temp->next;

Temp->next = newNode;

// Function to print the linked list


Void printList(struct Node *head) {

Struct Node *temp = head;

While (temp != NULL) {

Printf(“%d -> “, temp->data);

Temp = temp->next;

Printf(“NULL\n”);

Int main() {

Struct Node *head = NULL;

// Append nodes to the list

appendNode(&head, 10);

appendNode(&head, 20);

appendNode(&head, 30);

// Print the list

printList(head);

return 0;

```

### Explanation of the Example

1. **Structure Definition**:

- `struct Node` defines a node structure with an integer `data` and a pointer
`next` to another `Node`.

2. **Creating a Node**:

- `createNode` function allocates memory for a new node, initializes it with the
given data, and sets the `next` pointer to `NULL`.

3. **Appending a Node**:
- `appendNode` function adds a new node at the end of the linked list. If the list
is empty (`head` is `NULL`), the new node becomes the head. Otherwise, it
traverses the list to find the last node and sets its `next` pointer to the new node.

4. **Printing the List**:

- `printList` function traverses the list starting from the head, printing each
node’s data followed by an arrow (`->`). It ends with `NULL` to indicate the end of
the list.

### Key Concepts

1. **Dynamic Memory Allocation**:

- `malloc` from `<stdlib.h>` is used to allocate memory for new nodes.


Remember to `free` allocated memory when it is no longer needed to avoid
memory leaks.

2. **Pointer Manipulation**:

- Self-referential structures often involve manipulating pointers to traverse and


modify linked data structures.

3. **Function Pointers**:

- Complex operations on self-referential structures can sometimes be simplified


using function pointers, particularly in algorithms like sorting or searching in lists or
trees.

### Advantages and Uses

- **Linked Lists**: Efficient insertion and deletion operations.

- **Trees**: Binary trees, AVL trees, and other tree structures.

- **Graphs**: Adjacency list representations of graphs.

- **Stacks and Queues**: Implementations using linked lists.

Self-referential structures are a powerful feature in C, enabling the creation of


flexible and efficient data structures that can dynamically grow and shrink.
Understanding how to use and manipulate these structures is essential for effective
C programming, particularly in systems programming and applications that require
dynamic data management.
Student Marklist:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

// Define a structure to store student information

Struct Student {

Char name[50];

Int rollNo;

Float marks[5];

Float average;

};

// Function to input student details

Void inputStudentDetails(struct Student *s, int numSubjects) {

Printf(“Enter student name: “);

Scanf(“%s”, s->name);

Printf(“Enter roll number: “);

Scanf(“%d”, &s->rollNo);

Printf(“Enter marks for %d subjects:\n”, numSubjects);

For(int I = 0; I < numSubjects; i++) {

Printf(“Subject %d: “, I + 1);

Scanf(“%f”, &s->marks[i]);

}
// Function to calculate average marks

Void calculateAverage(struct Student *s, int numSubjects) {

Float sum = 0;

For(int I = 0; I < numSubjects; i++) {

Sum += s->marks[i];

s->average = sum / numSubjects;

// Function to display student details

Void displayStudentDetails(struct Student s, int numSubjects) {

Printf(“\nStudent Name: %s\n”, [Link]);

Printf(“Roll Number: %d\n”, [Link]);

Printf(“Marks:\n”);

For(int I = 0; I < numSubjects; i++) {

Printf(“Subject %d: %.2f\n”, I + 1, [Link][i]);

Printf(“Average Marks: %.2f\n”, [Link]);

Int main() {

Int numStudents, numSubjects;

Printf(“Enter the number of students: “);

Scanf(“%d”, &numStudents);

Printf(“Enter the number of subjects: “);

Scanf(“%d”, &numSubjects);

Struct Student students[numStudents];

For(int I = 0; I < numStudents; i++) {

Printf(“\nEnter details for student %d:\n”, I + 1);


inputStudentDetails(&students[i], numSubjects);

calculateAverage(&students[i], numSubjects);

Printf(“\nStudent Mark List:\n”);

For(int I = 0; I < numStudents; i++) {

displayStudentDetails(students[i], numSubjects);

Return 0;

Output:

Enter the number of students: 2

Enter the number of subjects: 3

Enter details for student 1:

Enter student name: Alice

Enter roll number: 1

Enter marks for 3 subjects:

Subject 1: 85

Subject 2: 90

Subject 3: 88

Enter details for student 2:

Enter student name: Bob

Enter roll number: 2

Enter marks for 3 subjects:

Subject 1: 75

Subject 2: 80

Subject 3: 78

Student Mark List:

Student Name: Alice


Roll Number: 1

Marks:

Subject 1: 85.00

Subject 2: 90.00

Subject 3: 88.00

Average Marks: 87.67

Student Name: Bob

Roll Number: 2

Marks:

Subject 1: 75.00

Subject 2: 80.00

Subject 3: 78.00

Average Marks: 77.67


Call by value and call by reference :

In C programming, “call by value” and “call by reference” are two ways of passing
arguments to functions. Understanding the difference between these two methods
is crucial for effective programming.

### Call by Value

In call by value, a copy of the actual parameter’s value is passed to the function.
The function works with this copy, and any changes made to the parameter inside
the function do not affect the original value.

#### Example

Here is an example demonstrating call by value:

```c

#include <stdio.h>

// Function that takes an integer by value

Void modifyValue(int num) {

Num = 20; // Change the value

Printf(“Inside modifyValue: num = %d\n”, num);

Int main() {

Int a = 10;

Printf(“Before modifyValue: a = %d\n”, a);

modifyValue(a);

printf(“After modifyValue: a = %d\n”, a); // Value of ‘a’ remains unchanged

return 0;

```

**Output**:

```

Before modifyValue: a = 10

Inside modifyValue: num = 20


After modifyValue: a = 10

```

**Explanation**:

- In the `main` function, the variable `a` is passed to `modifyValue`.

- Inside `modifyValue`, a local copy of `a` is modified.

- The original value of `a` in `main` remains unchanged because only a copy was
passed to the function.

### Call by Reference

In call by reference, a reference (or address) to the actual parameter is passed to


the function. This means the function operates on the original data. Any changes
made to the parameter inside the function affect the original value.

#### Example

Here is an example demonstrating call by reference:

```c

#include <stdio.h>

// Function that takes an integer pointer (address)

Void modifyValue(int *num) {

*num = 20; // Change the value at the address pointed to by num

Printf(“Inside modifyValue: *num = %d\n”, *num);

Int main() {

Int a = 10;

Printf(“Before modifyValue: a = %d\n”, a);

modifyValue(&a); // Pass the address of ‘a’

printf(“After modifyValue: a = %d\n”, a); // Value of ‘a’ is changed

return 0;

```

**Output**:
```

Before modifyValue: a = 10

Inside modifyValue: *num = 20

After modifyValue: a = 20

```

**Explanation**:

- In the `main` function, the address of `a` is passed to `modifyValue`.

- Inside `modifyValue`, the value at the address pointed to by `num` is modified.

- The original value of `a` in `main` is changed because the function operates on
the actual data through its address.

Function & its type :


In C programming, a function is a self-contained block of code that performs a
specific task. Functions help in modularizing the code, improving readability,
reusability, and maintainability. Functions can be broadly classified into several
types based on their functionality and usage.

### Types of Functions in C

1. **Library Functions**: Predefined functions provided by the C standard library


(e.g., `printf`, `scanf`, `strcpy`).

2. **User-defined Functions**: Functions created by the programmer to perform


specific tasks.

### Components of a Function

A typical function in C consists of the following parts:

1. **Return Type**: Specifies the type of value the function returns.

2. **Function Name**: The identifier used to call the function.

3. **Parameters**: A list of variables that the function takes as input.

4. **Function Body**: The block of code that defines what the function does.

### Example of a User-defined Function

Let’s create a simple program with a user-defined function to add two numbers.

```c

#include <stdio.h>

// Function prototype

Int add(int a, int b);

Int main() {

Int num1 = 5, num2 = 3, sum;

// Function call

Sum = add(num1, num2);

Printf(“Sum: %d\n”, sum);

Return 0;

// Function definition

Int add(int a, int b) {


Return a + b;

```

### Types of User-defined Functions

1. **No Return Type and No Parameters**

- Functions that do not take any input parameters and do not return any value.

```c

Void printMessage() {

Printf(“Hello, World!\n”);

```

2. **No Return Type but with Parameters**

- Functions that take input parameters but do not return any value.

```c

Void printSum(int a, int b) {

Int sum = a + b;

Printf(“Sum: %d\n”, sum);

```

3. **With Return Type but No Parameters**

- Functions that return a value but do not take any input parameters.

```c

Int getNumber() {

Int num = 10;

Return num;

```

4. **With Return Type and Parameters**


- Functions that take input parameters and return a value.

```c

Int multiply(int a, int b) {

Return a * b;

```

### Function Prototypes

A function prototype is a declaration of a function that specifies the function’s


name, return type, and parameters (without the function body). It informs the
compiler about the function’s existence before its actual definition

```c

Int add(int a, int b); // Function prototype

```

### Example Program with Different Types of Functions

Here is an example program that includes all types of user-defined functions:

```c

#include <stdio.h>

// Function prototypes

Void printMessage();

Void printSum(int a, int b);

Int getNumber();

Int multiply(int a, int b);

Int main() {

// No return type and no parameters

printMessage();

// No return type but with parameters

printSum(5, 3);

// With return type but no parameters


Int num = getNumber();

Printf(“Number: %d\n”, num);

// With return type and parameters

Int product = multiply(4, 6);

Printf(“Product: %d\n”, product);

Return 0;

// Function definitions

Void printMessage() {

Printf(“Hello, World!\n”);

Void printSum(int a, int b) {

Int sum = a + b;

Printf(“Sum: %d\n”, sum);

Int getNumber() {

Int num = 10;

Return num;

Int multiply(int a, int b) {

Return a * b;

```

### Explanation

1. **printMessage**:

- No return type (`void`).

- No parameters.
- Prints a message to the console.

2. **printSum**:

- No return type (`void`).

- Takes two integer parameters.

- Calculates and prints the sum of the parameters.

3. **getNumber**:

- Returns an integer.

- No parameters.

- Returns a fixed number.

4. **multiply**:

- Returns an integer.

- Takes two integer parameters.

- Returns the product of the parameters.

### Benefits of Using Functions

- **Modularity**: Breaks the program into smaller, manageable pieces.

- **Reusability**: Allows the same code to be reused multiple times without


duplication.

- **Readability**: Improves the readability of the program by organizing code into


logical sections.

- **Maintainability**: Makes it easier to update and maintain the code.

Functions are a fundamental concept in C programming, enabling the creation of


organized, modular, and reusable code. Understanding how to define, use, and
classify functions is essential for effective programming in C.

Linked list:

A linked list is a dynamic data structure that consists of a sequence of elements,


each containing a reference (or link) to the next element in the sequence. This
allows for efficient insertion and deletion of elements at any position in the list.
Linked lists are a fundamental data structure used in computer science and
programming.

### Types of Linked Lists

1. **Singly Linked List**: Each node contains data and a reference to the next node.

2. **Doubly Linked List**: Each node contains data, a reference to the next node,
and a reference to the previous node.

3. **Circular Linked List**: The last node points back to the first node, forming a
circular structure. This can be either singly or doubly linked.

### Basic Operations on a Singly Linked List

1. **Insertion**: Add a new node at the beginning, end, or any position in the list.

2. **Deletion**: Remove a node from the beginning, end, or any position in the list.

3. **Traversal**: Traverse the list to access or print the elements.

### Structure Definition

Here is the basic structure definition for a node in a singly linked list:

```c

Struct Node {

Int data;

Struct Node* next;

};

```

### Example Program: Singly Linked List

The following program demonstrates the creation, insertion, deletion, and traversal
of a singly linked list.

#### Complete Program

```c

#include <stdio.h>

#include <stdlib.h>

// Define the structure for a node

Struct Node {

Int data;
Struct Node* next;

};

// Function to create a new node

Struct Node* createNode(int data) {

Struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));

newNode->data = data;

newNode->next = NULL;

return newNode;

// Function to insert a node at the beginning of the list

Void insertAtBeginning(struct Node** head, int data) {

Struct Node* newNode = createNode(data);

newNode->next = *head;

*head = newNode;

// Function to insert a node at the end of the list

Void insertAtEnd(struct Node** head, int data) {

Struct Node* newNode = createNode(data);

If (*head == NULL) {

*head = newNode;

} else {

Struct Node* temp = *head;

While (temp->next != NULL) {

Temp = temp->next;

Temp->next = newNode;

}
// Function to delete a node with a given key

Void deleteNode(struct Node** head, int key) {

Struct Node* temp = *head;

Struct Node* prev = NULL;

// If the head node itself holds the key to be deleted

If (temp != NULL && temp->data == key) {

*head = temp->next;

Free(temp);

Return;

// Search for the key to be deleted

While (temp != NULL && temp->data != key) {

Prev = temp;

Temp = temp->next;

// If the key was not present in the list

If (temp == NULL) return;

// Unlink the node from the linked list

Prev->next = temp->next;

Free(temp);

// Function to traverse and print the linked list

Void printList(struct Node* head) {

Struct Node* temp = head;

While (temp != NULL) {

Printf(“%d -> “, temp->data);

Temp = temp->next;

}
Printf(“NULL\n”);

Int main() {

Struct Node* head = NULL;

insertAtEnd(&head, 1);

insertAtEnd(&head, 2);

insertAtEnd(&head, 3);

insertAtBeginning(&head, 0);

printList(head);

deleteNode(&head, 2);

printList(head);

return 0;

```

### Explanation of the Program

1. **Structure Definition**:

- `struct Node` defines the structure of a node, which contains an integer `data`
and a pointer `next` to the next node.

2. **Function Implementations**:

- `createNode`: Allocates memory for a new node, initializes it with the given
data, and sets the `next` pointer to `NULL`.

- `insertAtBeginning`: Inserts a new node at the beginning of the list by updating


the head pointer.

- `insertAtEnd`: Inserts a new node at the end of the list by traversing to the last
node and updating its `next` pointer.

- `deleteNode`: Deletes a node with a given key by searching for the node,
unlinking it from the list, and freeing its memory.

- `printList`: Traverses the list and prints the data of each node.

3. **Main Function**:
- Demonstrates the usage of the list operations by creating a list, inserting nodes
at both ends, deleting a node, and printing the list after each operation.

### Advantages of Linked Lists

- **Dynamic Size**: Can grow or shrink in size as needed, unlike arrays which have
a fixed size.

- **Efficient Insertions/Deletions**: Inserting or deleting a node is more efficient


(O(1) time complexity) if the position is known, compared to arrays which may
require shifting elements (O(n) time complexity).

### Disadvantages of Linked Lists

- **Memory Overhead**: Each node requires extra memory for the pointer.

- **Sequential Access**: Nodes must be accessed sequentially from the head,


making random access inefficient (O(n) time complexity)

Linked lists are a powerful and flexible data structure that provide efficient
insertions and deletions, making them ideal for certain types of problems where
dynamic data handling is required.

Dynamic memory allocation :

Dynamic memory allocation in C allows programs to request memory from the heap
at runtime, enabling the creation of data structures whose size is not known at
compile time. This provides flexibility for handling varying amounts of data.

### Key Functions for Dynamic Memory Allocation


The C standard library provides several functions for dynamic memory allocation, all
of which are declared in the `<stdlib.h>` header file:

1. **malloc**: Allocates a specified number of bytes and returns a pointer to the


allocated memory.

2. **calloc**: Allocates memory for an array of elements, initializes them to zero,


and returns a pointer to the allocated memory.

3. **realloc**: Changes the size of previously allocated memory.

4. **free**: Frees the allocated memory, making it available for future allocations.

### Function Details

1. **malloc (Memory Allocation)**

- Prototype: `void* malloc(size_t size);`

- Allocates `size` bytes of memory and returns a pointer to the beginning of the
block.

- The contents of the allocated memory are uninitialized.

```c

Int *ptr = (int*) malloc(10 * sizeof(int));

If (ptr == NULL) {

Printf(“Memory allocation failed\n”);

Return 1;

```

2. **calloc (Contiguous Allocation)**

- Prototype: `void* calloc(size_t num, size_t size);`

- Allocates memory for an array of `num` elements, each of `size` bytes.

- Initializes all bytes in the allocated storage to zero.

```c

Int *ptr = (int*) calloc(10, sizeof(int));

If (ptr == NULL) {

Printf(“Memory allocation failed\n”);

Return 1;
}

```

3. **realloc (Reallocation)**

- Prototype: `void* realloc(void* ptr, size_t newSize);`

- Changes the size of the memory block pointed to by `ptr` to `newSize` bytes.

- The contents of the memory block are preserved up to the lesser of the new and
old sizes.

```c

Int *ptr = (int*) malloc(10 * sizeof(int));

// Later, resize the memory block

Ptr = (int*) realloc(ptr, 20 * sizeof(int));

If (ptr == NULL) {

Printf(“Memory reallocation failed\n”);

Return 1;

```

4. **free (Deallocate Memory)**

- Prototype: `void free(void* ptr);`

- Frees the memory space pointed to by `ptr`, which must have been returned by
a previous call to `malloc`, `calloc`, or `realloc`.

```c

Free(ptr);

```

### Example Program Using Dynamic Memory Allocation

The following example demonstrates dynamic memory allocation using `malloc`,


`calloc`, `realloc`, and `free`.

```c

#include <stdio.h>

#include <stdlib.h>
Int main() {

Int n, I;

Int *ptr;

Printf(“Enter the number of elements: “);

Scanf(“%d”, &n);

// Using malloc to allocate memory

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

If (ptr == NULL) {

Printf(“Memory allocation failed\n”);

Return 1;

// Using calloc to allocate memory

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

// if (ptr == NULL) {

// printf(“Memory allocation failed\n”);

// return 1;

// }

Printf(“Enter the elements:\n”);

For (I = 0; I < n; i++) {

Scanf(“%d”, &ptr[i]);

Printf(“You entered:\n”);

For (I = 0; I < n; i++) {

Printf(“%d “, ptr[i]);

Printf(“\n”);

// Using realloc to resize the allocated memory


Int newSize;

Printf(“Enter the new size: “);

Scanf(“%d”, &newSize);

Ptr = (int*) realloc(ptr, newSize * sizeof(int));

If (ptr == NULL) {

Printf(“Memory reallocation failed\n”);

Return 1;

Printf(“Enter the new elements:\n”);

For (I = n; I < newSize; i++) {

Scanf(“%d”, &ptr[i]);

Printf(“You entered:\n”);

For (I = 0; I < newSize; i++) {

Printf(“%d “, ptr[i]);

Printf(“\n”);

// Freeing the allocated memory

Free(ptr);

Return 0;

```

### Explanation

1. **Memory Allocation with malloc**:

- The program first allocates memory for `n` integers using `malloc`.

- If memory allocation fails, it prints an error message and exits.

2. **Input and Output**:


- The program prompts the user to enter `n` elements and stores them in the
allocated memory.

- It then prints the entered elements.

3. **Memory Reallocation with realloc**:

- The program asks for a new size and reallocates memory using `realloc`.

- It then prompts the user to enter the additional elements and prints the entire
list.

4. **Freeing Memory**:

- Finally, the allocated memory is freed using `free`.

### Benefits of Dynamic Memory Allocatio

- **Flexibility**: Allows allocation of memory as needed at runtime.

- **Efficient Memory Usage**: Minimizes memory wastage by allocating only the


required amount.

- **Variable Size Data Structures**: Supports creation of data structures like linked
lists, trees, and graphs, where the size can change dynamically.

### Caveats and Best Practices

- **Memory Leaks**: Ensure every allocated block of memory is freed to avoid


memory leaks.

- **NULL Checks**: Always check the return value of `malloc`, `calloc`, and
`realloc` to ensure memory allocation was successful.

- **Avoid Dangling Pointers**: After freeing memory, set the pointer to `NULL` to
avoid dangling pointers.

Dynamic memory allocation is a powerful feature in C that, when used correctly,


provides great flexibility and efficiency in managing memory for complex data
structures and variable-sized data.

You might also like