0% found this document useful (0 votes)
31 views24 pages

Unit III Pointers Part B and Dynamic Memory Allocation

The document provides an extensive overview of pointers and arrays in C, detailing their relationship and usage through various examples. It covers topics such as passing arrays to functions, function pointers, call by reference and value, pointers to pointers, and dynamic memory allocation. Each section includes code snippets and explanations to illustrate the concepts effectively.

Uploaded by

jaua767
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)
31 views24 pages

Unit III Pointers Part B and Dynamic Memory Allocation

The document provides an extensive overview of pointers and arrays in C, detailing their relationship and usage through various examples. It covers topics such as passing arrays to functions, function pointers, call by reference and value, pointers to pointers, and dynamic memory allocation. Each section includes code snippets and explanations to illustrate the concepts effectively.

Uploaded by

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

1.

Pointers and Arrays

Pointers and Arrays Overview: In C, pointers and arrays have a close relationship. A pointer can
store the address of an array element, allowing efficient access and manipulation. An array
name acts as a pointer to the first element, enabling pointer arithmetic.

Example 1: Accessing Array Elements Using a Pointer

#include <stdio.h>

int main() {
int arr[3] = {10, 20, 30};
int *ptr = arr;

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


printf("*(ptr + %d) = %d\n", i, *(ptr + i));
}
return 0;
}

Output Explanation:
The pointer ptr accesses each element in the array arr using pointer arithmetic. *(ptr + i)
retrieves arr[i].

---

Example 2: Modifying Array Elements Using a Pointer

#include <stdio.h>

int main() {
int arr[3] = {5, 15, 25};
int *ptr = arr;

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


*(ptr + i) += 10;
printf("Updated arr[%d] = %d\n", i, arr[i]);
}
return 0;
}

Output Explanation:
Each array element is modified by adding 10 through the pointer ptr. The changes reflect in the
original array arr.

---

Example 3: Using arr as a Pointer

#include <stdio.h>

int main() {
int arr[3] = {3, 6, 9};

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


printf("*(arr + %d) = %d\n", i, *(arr + i));
}
return 0;
}

Output Explanation:
Since arr acts as a pointer to its first element, *(arr + i) accesses each element directly.

---

Example 4: Printing Addresses of Array Elements

#include <stdio.h>

int main() {
int arr[3] = {100, 200, 300};

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


printf("Address of arr[%d] = %p\n", i, (void*)&arr[i]);
}
return 0;
}

Output Explanation:
Each element’s address is printed, showing how the array elements are sequentially stored in
memory.

---
2. Passing Arrays to Functions

Overview:
When an array is passed to a function, it is effectively a pointer to the array's first element,
allowing the function to access and modify elements.

Example 1: Displaying Array Elements

#include <stdio.h>

void display(int arr[], int size) {


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

int main() {
int arr[3] = {4, 8, 12};
display(arr, 3);
return 0;
}

Output Explanation:
display receives arr as a pointer and prints each element.

---

Example 2: Modifying Array Elements

#include <stdio.h>

void modify(int arr[], int size) {


for (int i = 0; i < size; i++) {
arr[i] += 5;
}
}

int main() {
int arr[3] = {2, 4, 6};
modify(arr, 3);
for (int i = 0; i < 3; i++) {
printf("arr[%d] = %d\n", i, arr[i]);
}
return 0;
}

Output Explanation:
modify changes arr elements directly, demonstrating array modifications within a function.

---

Example 3: Finding Maximum Element

#include <stdio.h>

int findMax(int arr[], int size) {


int max = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}

int main() {
int arr[3] = {5, 15, 10};
printf("Max element: %d\n", findMax(arr, 3));
return 0;
}

Output Explanation:
The function finds the maximum value in arr without needing to return the array itself.

---

Example 4: Summing Array Elements

#include <stdio.h>

int sum(int arr[], int size) {


int total = 0;
for (int i = 0; i < size; i++) {
total += arr[i];
}
return total;
}

int main() {
int arr[4] = {1, 2, 3, 4};
printf("Sum of elements: %d\n", sum(arr, 4));
return 0;
}

Output Explanation:
The sum function calculates the total sum of arr elements.

---

3. Array of Pointers

Overview:
An array of pointers holds the addresses of multiple variables or strings, each pointing to distinct
data.

Example 1: Array of Strings

#include <stdio.h>

int main() {
const char *cities[] = {"New York", "Paris", "Tokyo"};

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


printf("City: %s\n", cities[i]);
}
return 0;
}

Output Explanation:
Each cities[i] points to a different string, allowing efficient handling of multiple strings.

---

Example 2: Array of Integer Pointers


#include <stdio.h>

int main() {
int a = 5, b = 10, c = 15;
int *arr[3] = {&a, &b, &c};

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


printf("Value of arr[%d]: %d\n", i, *arr[i]);
}
return 0;
}

Output Explanation:
Each element of arr points to an integer, showing how arrays of pointers manage different
variables.

---

4. Function Pointers

Definition and Description:


A function pointer is a pointer that points to a function rather than a variable. Function pointers
can be used to call functions dynamically, allowing for more flexible and reusable code. They
are commonly used in scenarios where you want to pass a function as an argument, such as
with callback functions.

Example 1: Basic Function Pointer

#include <stdio.h>

void greet() {
printf("Hello!\n");
}

int main() {
void (*func_ptr)() = greet; // Declaring a function pointer
func_ptr(); // Calling the function through the pointer
return 0;
}

Output Explanation:
In this example, func_ptr is a pointer to the greet function. Calling func_ptr() executes greet,
printing "Hello!".
---

Example 2: Function Pointer with Parameters

#include <stdio.h>

void add(int a, int b) {


printf("Sum: %d\n", a + b);
}

int main() {
void (*func_ptr)(int, int) = add;
func_ptr(5, 10); // Calling add with parameters 5 and 10
return 0;
}

Output Explanation:
func_ptr is a pointer to add. Calling func_ptr(5, 10) executes add, outputting "Sum: 15".

---

Example 3: Using Function Pointers in an Array

#include <stdio.h>

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


void subtract(int a, int b) { printf("Subtract: %d\n", a - b); }

int main() {
void (*operations[])(int, int) = {add, subtract};
operations[0](10, 5); // Calls add
operations[1](10, 5); // Calls subtract
return 0;
}

Output Explanation:
An array of function pointers (operations) holds add and subtract. operations[0](10, 5) calls add,
and operations[1](10, 5) calls subtract.

---
Example 4: Passing Function Pointers as Arguments

#include <stdio.h>

void multiply(int a, int b) {


printf("Product: %d\n", a * b);
}

void executeOperation(void (*func_ptr)(int, int), int x, int y) {


func_ptr(x, y);
}

int main() {
executeOperation(multiply, 4, 5);
return 0;
}

Output Explanation:
executeOperation receives a function pointer and calls it with x and y. Here, it calls multiply,
outputting "Product: 20".

---

6. Call by Reference

Definition and Description:


In "call by reference," a function receives a reference (address) of the argument, allowing it to
modify the original variable’s value. This is typically done using pointers in C.

Example 1: Modifying a Variable through Reference

#include <stdio.h>

void changeValue(int *num) {


*num = 100;
}

int main() {
int x = 50;
changeValue(&x);
printf("Modified x: %d\n", x);
return 0;
}
Output Explanation:
The changeValue function receives the address of x and changes its value to 100. The original
variable x is modified, and the output is "Modified x: 100".

---

Example 2: Swapping Two Numbers Using Call by Reference

#include <stdio.h>

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


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

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

Output Explanation:
The swap function receives pointers to x and y, allowing it to swap their values directly. The
output shows "After swapping: x = 10, y = 5".

---

Example 3: Changing Array Elements through Reference

#include <stdio.h>

void increaseElements(int *arr, int size) {


for (int i = 0; i < size; i++) {
arr[i] += 10;
}
}

int main() {
int numbers[] = {1, 2, 3};
increaseElements(numbers, 3);
for (int i = 0; i < 3; i++) {
printf("numbers[%d] = %d\n", i, numbers[i]);
}
return 0;
}

Output Explanation:
The function increaseElements modifies numbers directly, increasing each element by 10. The
output reflects these changes.

---

7. Call by Value

Definition and Description:


In "call by value," a function receives a copy of the argument, so changes within the function do
not affect the original variable outside.

Example 1: No Change to Original Variable

#include <stdio.h>

void modify(int num) {


num = 100;
}

int main() {
int x = 50;
modify(x);
printf("Unmodified x: %d\n", x);
return 0;
}

Output Explanation:
modify changes only the copy of x, so the original x remains 50. The output is "Unmodified x:
50".

---

Example 2: Summing Two Numbers (No Change to Original Values)


#include <stdio.h>

void sum(int a, int b) {


int result = a + b;
printf("Sum: %d\n", result);
}

int main() {
int x = 3, y = 7;
sum(x, y);
printf("x: %d, y: %d\n", x, y);
return 0;
}

Output Explanation:
The function calculates the sum of x and y, but their original values are unchanged outside the
function.

---

My apologies for that! Here is a detailed section on Pointers to Pointers with definitions,
descriptions, and multiple examples including code and output explanations.

---

8. Pointers to Pointers

Definition and Description:


A "pointer to a pointer" (also known as a double pointer) is a variable that stores the address of
another pointer. This is represented by using ** syntax in C. Double pointers are useful when
working with dynamic memory allocation for multi-dimensional arrays, or when passing a
pointer's address to a function to modify the original pointer.

A pointer to a pointer can indirectly access values that are two levels away in memory. They are
often used in complex data structures and in situations requiring indirect referencing, such as
modifying pointer values inside functions.

---

Example 1: Basic Pointer to Pointer Usage


#include <stdio.h>

int main() {
int x = 10;
int *p = &x; // p is a pointer to x
int **pp = &p; // pp is a pointer to p

printf("Value of x: %d\n", x);


printf("Value pointed to by p: %d\n", *p);
printf("Value pointed to by pp: %d\n", **pp);

return 0;
}

Output Explanation:

x is an integer with a value of 10.

p is a pointer to x, so *p outputs the value of x.

pp is a pointer to p, so **pp dereferences twice to access the value of x.


The output confirms that pp indirectly points to x.

---

Example 2: Modifying a Variable through a Pointer to a Pointer

#include <stdio.h>

void modify(int **pp) {


**pp = 20; // Modifies the value that pp points to
}

int main() {
int x = 10;
int *p = &x;
int **pp = &p;

printf("Original x: %d\n", x);


modify(pp); // Passes address of p to modify x
printf("Modified x: %d\n", x);
return 0;
}

Output Explanation:
In this example, the modify function takes a double pointer pp, which points to p, and modifies
the value of x by setting **pp to 20. The original x is changed, resulting in the output "Modified x:
20".

---

Example 3: Using Pointers to Pointers in Dynamic Memory Allocation for 2D Arrays

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

int main() {
int rows = 2, cols = 3;
int **arr = (int **)malloc(rows * sizeof(int *)); // Allocate array of int pointers

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


arr[i] = (int *)malloc(cols * sizeof(int)); // Allocate array for each row
for (int j = 0; j < cols; j++) {
arr[i][j] = i * cols + j; // Assign values to array elements
}
}

// Print the 2D array


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

// Free allocated memory


for (int i = 0; i < rows; i++) {
free(arr[i]);
}
free(arr);

return 0;
}
Output Explanation:
This program creates a 2D array dynamically using pointers to pointers:

1. arr is a double pointer pointing to an array of integer pointers (each representing a row).

2. Each row pointer points to an array of integers (representing columns).

3. The output displays a 2x3 grid with elements initialized as 0 1 2 and 3 4 5.

4. After printing, memory is freed to avoid memory leaks.

---

Example 4: Changing the Address of a Pointer through a Pointer to a Pointer

#include <stdio.h>

void changePointer(int **pp, int *newPtr) {


*pp = newPtr; // Modify the pointer that pp points to
}

int main() {
int a = 5, b = 15;
int *p = &a;
int **pp = &p;

printf("Original value pointed to by p: %d\n", *p);


changePointer(pp, &b); // Change p to point to b
printf("New value pointed to by p: %d\n", *p);

return 0;
}

Output Explanation:
This program demonstrates how a double pointer can change which variable a pointer points to.

Initially, p points to a (value 5).


The changePointer function changes p to point to b (value 15).
The output verifies the change, showing that p now points to b after calling the function.

---
Dynamic Memory Allocation in C

Dynamic memory allocation allows a program to request memory from the heap at runtime,
unlike static memory allocation, which is determined at compile time. C provides several
functions for dynamic memory management: malloc(), calloc(), realloc(), and free().

1. Memory Allocation Process

Dynamic memory allocation is crucial when the size of data structures like arrays or linked lists
cannot be determined until runtime. The functions mentioned allocate memory in the "heap"
region, which the program manages explicitly.

2. malloc() (Memory Allocation)

Definition and Description:


The malloc() function allocates a specified number of bytes in memory and returns a pointer to
the beginning of the allocated block. Memory is not initialized, so it contains "garbage" values.

Syntax:

void *malloc(size_t size);

Example 1: Basic Usage of malloc()

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

int main() {
int *ptr;
ptr = (int *)malloc(sizeof(int) * 3); // Allocates memory for 3 integers

// Access uninitialized memory (may contain garbage values)


for (int i = 0; i < 3; i++) {
printf("%d ", ptr[i]);
}
free(ptr); // Free the allocated memory
return 0;
}

Output Explanation:
Since malloc() does not initialize memory, the output will show random garbage values. Each
memory location contains whatever data was previously stored there.
---

Example 2: Initializing Allocated Memory with malloc()

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

int main() {
int *ptr;
ptr = (int *)malloc(sizeof(int) * 3); // Allocates memory for 3 integers

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


ptr[i] = i + 1; // Initialize memory
}

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


printf("%d ", ptr[i]);
}

free(ptr); // Free the allocated memory


return 0;
}

Output Explanation:
The output will be 1 2 3, as we explicitly set values in allocated memory. This ensures consistent
output.

---

3. calloc() (Contiguous Allocation)

Definition and Description:


The calloc() function allocates memory for an array of elements, initializing all bits to zero. This
makes it suitable for cases where you need initialized memory.

Syntax:

void *calloc(size_t num_elements, size_t size_of_element);

Example 1: Basic Usage of calloc()

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

int main() {
int *ptr;
ptr = (int *)calloc(3, sizeof(int)); // Allocates memory for 3 integers, initialized to 0

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


printf("%d ", ptr[i]);
}
free(ptr); // Free the allocated memory
return 0;
}

Output Explanation:
Output will be 0 0 0, as calloc() initializes all allocated memory to zero, unlike malloc().

---

Example 2: Using calloc() for Array Memory Allocation

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

int main() {
int *arr = (int *)calloc(5, sizeof(int)); // Allocates memory for an array of 5 integers

// Setting values in the array


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

free(arr); // Free the allocated memory


return 0;
}

Output Explanation:
The output is 0 2 4 6 8. The array is initialized to zero, and then each element is set to double its
index.

---
4. realloc() (Reallocation)

Definition and Description:


The realloc() function changes the size of previously allocated memory. It may move the data if
a larger block is needed. When shrinking, it retains the original data up to the new size.

Syntax:

void *realloc(void *ptr, size_t new_size);

Example 1: Expanding an Array Using realloc()

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

int main() {
int *arr = (int *)malloc(2 * sizeof(int));
arr[0] = 1;
arr[1] = 2;

arr = (int *)realloc(arr, 4 * sizeof(int)); // Expand to 4 integers

arr[2] = 3;
arr[3] = 4;

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


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

free(arr); // Free the allocated memory


return 0;
}

Output Explanation:
The output will be 1 2 3 4. The realloc() function expands the memory block, preserving the
original values, and allows us to add more data.

---

Example 2: Reducing Array Size with realloc()

#include <stdio.h>
#include <stdlib.h>
int main() {
int *arr = (int *)malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}

arr = (int *)realloc(arr, 3 * sizeof(int)); // Reduce to 3 integers

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


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

free(arr); // Free the allocated memory


return 0;
}

Output Explanation:
Output will be 1 2 3. The array size is reduced, and the first three elements are retained. The
last two elements are discarded.

---

5. free() (Freeing Memory)

Definition and Description:


The free() function deallocates the memory previously allocated by malloc(), calloc(), or
realloc(). Once freed, the pointer becomes invalid, and accessing it can lead to undefined
behavior.

Syntax:

void free(void *ptr);

Example 1: Freeing Memory Allocated with malloc()

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

int main() {
int *ptr = (int *)malloc(3 * sizeof(int));
if (ptr == NULL) {
printf("Memory allocation failed\n");
return 1;
}

free(ptr); // Deallocate memory


// ptr is now a dangling pointer, should not be used
return 0;
}

Output Explanation:
No specific output, but memory allocated to ptr is freed, and further access is prevented,
avoiding memory leaks.

---

Example 2: Freeing Memory Allocated with calloc()

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

int main() {
int *arr = (int *)calloc(3, sizeof(int));

free(arr); // Deallocate memory


return 0;
}

Output Explanation:
The memory allocated by calloc() is released with free(). No output is expected, but it ensures
resources are properly managed.

---

Example 3: Freeing Memory in a Program with realloc()

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

int main() {
int *arr = (int *)malloc(3 * sizeof(int));
arr = (int *)realloc(arr, 5 * sizeof(int)); // Expands memory

free(arr); // Free expanded memory


return 0;
}

Output Explanation:
This ensures all dynamically allocated memory is freed, preventing memory leaks.

---

Additional Topic

Pointers and Dynamic Memory Allocation

Definition and Description:


Dynamic memory allocation allows a program to request memory at runtime. Functions like
malloc, calloc, and free are used to manage memory dynamically, which is essential in
applications with variable-sized data.

Example 1: Allocating and Freeing Memory with malloc

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

int main() {
int *ptr = (int*)malloc(sizeof(int) * 3);
ptr[0] = 1;
ptr[1] = 2;
ptr[2] = 3;

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


printf("ptr[%d] = %d\n", i, ptr[i]);
}

free(ptr);
return 0;
}

Output Explanation:
Memory is allocated for 3 integers, and values are assigned. free(ptr) releases the memory after
use.

---

Example 2: Using calloc for Zero-Initialized Memory

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

int main() {
int *ptr = (int*)calloc(3, sizeof(int)); // Allocates zero-initialized memory

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


printf("ptr[%d] = %d\n", i, ptr[i]);
}

free(ptr);
return 0;
}

Output Explanation:
calloc allocates and initializes memory to zero. The output confirms that ptr values are initially
zero.

---

Example 3: Reallocating Memory with realloc

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

int main() {
int *ptr = (int*)malloc(2 * sizeof(int));
ptr[0] = 5;
ptr[1] = 10;

ptr = (int*)realloc(ptr, 4 * sizeof(int));


ptr[2] = 15;
ptr[3] = 20;

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


printf("ptr[%d] = %d\n", i, ptr[i]);
}

free(ptr);
return 0;
}

Output Explanation:
realloc expands ptr to hold more values. The output shows the updated array after reallocation.

You might also like