Pointers are a fundamental and powerful concept in C++, essential for low-level memory management and efficient array and string manipulation.
This comprehensive article provides 30 C++ pointer exercises, designed to advance your skills from beginner fundamentals to advanced usage.
Each exercise provides a clear problem statement, a helpful hint, a complete C++ solution, and a detailed explanation, ensuring you not only solve the problem but deeply understand why the solution works
What You’ll Practice
The challenges cover the following core topics:
- Pointers Fundamentals: Declaration, dereferencing (
*), address-of (&), size comparison, and null safety (nullptr). - Pointer Arithmetic: Array traversal (
ptr + N,ptr++) and accessing elements in arrays and C-style strings (char*). - Pointers and Functions: Pass-by-pointer (modifying external variables) and returning pointers.
- Function Pointers: Using function pointers and
typedefto implement the callback mechanism. - Dynamic Memory Management: Allocation (
new,new[]), deallocation (delete,delete[]), and demonstrating memory leaks. - Advanced Syntax: Pointers to Structs (using
->), Constant Pointers (constpositioning), and arrays of pointers.
+ Table Of Contents
Table of contents
- Exercise 1: Declaration and Dereference
- Exercise 2: Changing Value via Pointer
- Exercise 3: Pointer-to-Pointer (Double Pointer)
- Exercise 4: Pointer Arithmetic (Increment)
- Exercise 5: Pointer Arithmetic (Index Access)
- Exercise 6: Pointer Arithmetic on char Array
- Exercise 7: NULL Pointer Check
- Exercise 8: Simple Pass-by-Pointer Function
- Exercise 9: Size Comparison
- Exercise 10: Array Summation
- Exercise 11: Reverse Array
- Exercise 12: Finding Minimum
- Exercise 13: 2D Array Traversal
- Exercise 14: Copying an Array
- Exercise 15: Comparing Arrays
- Exercise 16: Sub-array Printing
- Exercise 17: Pass-by-Pointer (Swap)
- Exercise 18: Modifying String in Function
- Exercise 19: Function Pointer Declaration
- Exercise 20: Callback Function
- Exercise 21: Pointer to Constant Data
- Exercise 22: Constant Pointer
- Exercise 23: Pointer to Struct
- Exercise 24: Dynamic Allocation (Single Variable)
- Exercise 25: Dynamic Allocation (Array)
- Exercise 26: Array of Pointers
- Exercise 27: Finding a Substring
- Exercise 28: Memory Leak Demonstration
- Exercise 29: Reallocation Simulation
- Exercise 30: Linked List Node (Concept)
Exercise 1: Declaration and Dereference
Problem Statement: Declare an integer variable named value and initialize it to 100. Declare an integer pointer named ptr. Assign the memory address of value to ptr. Finally, print the integer stored in value by using only the pointer ptr and the dereference operator.
Expected Output:
The value is: 100
+ Hint
- Use the address-of operator (ampersand:
&) to get the memory location of the variable. - Use the dereference operator (asterisk:
*) to access the data stored at the memory location held by the pointer.
+ Show Solution
#include <iostream>
int main() {
int value = 100;
int* ptr;
// 1. Assign the address of 'value' to 'ptr'
ptr = &value;
// 2. Print the value using the pointer and dereference operator
std::cout << "The value is: " << *ptr << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The line
int* ptr;declares a pointer variable namedptrthat is designed to hold the memory address of an integer. - The line
ptr = &value;uses the address-of operator (&) to load the actual memory address ofvalueinto the pointerptr. - Finally,
*ptris the dereference operation, which follows the pointer’s address to retrieve the data (the integer 100) stored at that location.
Exercise 2: Changing Value via Pointer
Problem Statement: Declare an integer variable named number initialized to 50. Declare an integer pointer named num_ptr and make it point to number. Change the value of number to 99 using only the pointer num_ptr. Print the final value of the variable number.
Expected Output:
The final value of number is: 99
+ Hint
The dereference operator (*) can be used on the left side of an assignment operator (=) to modify the value that the pointer is currently pointing to.
+ Show Solution
#include <iostream>
int main() {
int number = 50;
int* num_ptr = &number;
// Change the value of 'number' using only the pointer
*num_ptr = 99;
// Print the final value of the variable 'number'
std::cout << "The final value of number is: " << number << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The statement
int* num_ptr = &number;initializes the pointer to hold the address ofnumber. - The key line is
*num_ptr = 99;. The*num_ptrexpression refers to the data at the address stored innum_ptr(which is the variablenumber). Assigning 99 to this expression directly modifies the content of the variablenumberitself.
Exercise 3: Pointer-to-Pointer (Double Pointer)
Problem Statement: Declare an integer variable x initialized to 42. Declare an integer pointer p1 that points to x. Declare a double integer pointer (pointer to a pointer) p2 that points to p1. Access and print the initial value of x using the double pointer p2.
Expected Output:
The value accessed via double pointer is: 42
+ Hint
A double pointer requires two asterisks (**) in its declaration. To access the final value, you will need to apply the dereference operator (*) twice
+ Show Solution
#include <iostream>
int main() {
int x = 42;
int* p1 = &x; // p1 points to x
int** p2 = &p1; // p2 points to p1
// Access the value of x using the double pointer p2
std::cout << "The value accessed via double pointer is: " << **p2 << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The pointer
p1holds the address ofx. The double pointerp2holds the address ofp1. - The expression
*p2dereferencesp2, which results in the content ofp1(the address ofx). - The expression
**p2then dereferences this result (the address ofx), which finally gives us the integer value 42 stored inx. - This structure is used in more complex data structures or when implementing pass-by-reference for pointers.
Exercise 4: Pointer Arithmetic (Increment)
Problem Statement: Declare an integer array named data with the elements {10, 20, 30, 40, 50}. Declare an integer pointer data_ptr and point it to the first element of the array. Use pointer increment (ptr++) and the dereference operator to traverse the array and print all five elements.
Given:
int data[] = {10, 20, 30, 40, 50};Code language: C++ (cpp)
Expected Output:
Elements using pointer increment: 10 20 30 40 50
+ Hint
- C++ knows the size of the underlying data type.
- When you increment an integer pointer, it automatically moves to the next integer in memory by adding
sizeof(int)bytes, which is exactly one element away in an array.
+ Show Solution
#include <iostream>
int main() {
int data[] = {10, 20, 30, 40, 50};
int size = sizeof(data) / sizeof(data[0]);
// Initialize pointer to the start of the array
int* data_ptr = data;
std::cout << "Elements using pointer increment: ";
for (int i = 0; i < size; ++i) {
// Print the value the pointer currently points to
std::cout << *data_ptr << " ";
// Move the pointer to the next element
data_ptr++;
}
std::cout << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The line
int* data_ptr = data;initializes the pointer to the base address of the array. Inside the loop,*data_ptraccesses the current element. - The key operation is
data_ptr++. Sincedata_ptris an integer pointer, this operation addssizeof(int)bytes to the address, effectively moving the pointer to the memory address of the next integer element in the array.
Exercise 5: Pointer Arithmetic (Index Access)
Problem Statement: Declare an integer array named scores with elements {85, 90, 78, 95, 88}. Declare a pointer score_ptr and point it to the first element. Access and print the third element (which is 78) of the array using pointer arithmetic in the form *(ptr + N).
Given:
int scores[] = {85, 90, 78, 95, 88};Code language: C++ (cpp)
Expected Output:
The value of the third element is: 78
+ Hint
- The third element is at index 2. To access it via pointer arithmetic, you must add 2 to the base pointer.
- Remember that
ptr + 2calculates the address, and the dereference operator (*) retrieves the value at that address.
+ Show Solution
#include <iostream>
int main() {
int scores[] = {85, 90, 78, 95, 88};
// Pointer points to the first element (scores[0])
int* score_ptr = scores;
// Access the third element (index 2) using pointer arithmetic
int third_element = *(score_ptr + 2);
std::cout << "The value of the third element is: " << third_element << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The expression
score_ptr + 2performs pointer arithmetic, calculating the address ofscores[2]by adding two times the size of an integer to the base address. - The outer dereference operator (
*) then retrieves the value (78) at that calculated memory address. This demonstrates that usingscores[i]is functionally equivalent to using*(scores + i).
Exercise 6: Pointer Arithmetic on char Array
Problem Statement: Declare a char array word[] = "CODE". Declare a char pointer p pointing to the beginning of the array. Use pointer arithmetic (p + N) and the dereference operator to print the third character (‘D’) of the array.
Expected Output:
The third character is: D
+ Hint
The third character is at index 2. Pointer arithmetic for the third element is *(p + 2).
+ Show Solution
#include <iostream>
int main() {
char word[] = "CODE";
char* p = word;
// Access the third character (index 2)
char third_char = *(p + 2);
std::cout << "The third character is: " << third_char << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- This confirms that pointer arithmetic works the same way for
chararrays as it does forintarrays. - Since
charis typically 1 byte,p + 2moves the pointer exactly two bytes forward to the memory location of the third character.
Exercise 7: NULL Pointer Check
Problem Statement: Declare an integer pointer named safe_ptr and initialize it to nullptr. Write a conditional statement to check if the pointer is null before attempting to dereference it. If it is null, print “Pointer is null, cannot dereference.” If it is not null, initialize a variable, assign its address to the pointer, and print the dereferenced value.
Expected Output:
Pointer is null, cannot dereference.
Pointer is now valid. Dereferenced value: 77
+ Hint
Always check if a pointer is not nullptr before using the dereference operator (*). Dereferencing a null pointer leads to undefined behavior, often a program crash.
+ Show Solution
#include <iostream>
int main() {
int* safe_ptr = nullptr;
if (safe_ptr == nullptr) {
std::cout << "Pointer is null, cannot dereference." << std::endl;
// Safely assign a valid address for the second check
int valid_data = 77;
safe_ptr = &valid_data;
}
// Now, we can safely check again and dereference if assigned
if (safe_ptr != nullptr) {
std::cout << "Pointer is now valid. Dereferenced value: " << *safe_ptr << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The initialization
int* safe_ptr = nullptr;explicitly sets the pointer to a known, invalid state. The firstifstatement checks this state usingsafe_ptr == nullptr. - This is a crucial safety check to prevent crashes. The second part demonstrates assigning a valid address (
&valid_data) and then safely using the pointer only after verifying it’s no longer null.
Exercise 8: Simple Pass-by-Pointer Function
Problem Statement: Write a function named increment_value that takes an integer pointer as its only argument. Inside the function, increment the value that the pointer points to by 10. In main, call the function using the address of an integer variable and print the updated value.
Expected Output:
Before increment: 50
After increment: 60
+ Hint
The function signature should be void increment_value(int* ptr). To modify the value, use the expression *ptr += 10;.
+ Show Solution
#include <iostream>
// Function accepts a pointer and modifies the original value
void increment_value(int* ptr) {
if (ptr != nullptr) {
// Dereference the pointer to access and change the value
*ptr += 10;
}
}
int main() {
int counter = 50;
std::cout << "Before increment: " << counter << std::endl;
// Pass the address of 'counter'
increment_value(&counter);
std::cout << "After increment: " << counter << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- This exercise is a basic demonstration of pass-by-pointer.
- By passing the address (
&counter), the function receives a pointer (ptr) that allows it to directly access and modify the original variable (counter) in the calling function’s memory space, which is impossible with standard pass-by-value.
Exercise 9: Size Comparison
Problem Statement: Declare an integer variable i and an integer pointer ptr. Use the sizeof() operator to print the size (in bytes) of the i variable and the size of the ptr pointer on your system. Note and discuss the difference between the two sizes.
Expected Output:
Size of an int variable: 4 bytes
Size of an int pointer (address): 8 bytes
+ Hint
- The size of a variable depends on its data type (e.g., typically 4 bytes for an
int). - The size of a pointer depends on the architecture of the system (e.g., 8 bytes for 64-bit systems), as it must be large enough to hold any memory address.
+ Show Solution
#include <iostream>
int main() {
int i = 0;
int* ptr = &i;
std::cout << "Size of an int variable: " << sizeof(i) << " bytes" << std::endl;
std::cout << "Size of an int pointer (address): " << sizeof(ptr) << " bytes" << std::endl;
return 0;
}
/* Expected Output on a typical 64-bit system:
Size of an int variable: 4 bytes
Size of an int pointer (address): 8 bytes
*/Code language: C++ (cpp)
Explanation:
- The
sizeof(i)reports the size required to store the actual integer data (usually 4 bytes). - The
sizeof(ptr)reports the size required to store a memory address itself. This size is determined by the system’s architecture (32-bit or 64-bit). - The key takeaway is that the size of a pointer is constant regardless of the type it points to, because it only stores an address.
Exercise 10: Array Summation
Problem Statement: Write a program to calculate and print the sum of all elements in a given integer array {1, 5, 10, 15, 20} using only pointer arithmetic to access the elements. Do not use the array index operator ([]).
Expected Output:
The sum of array elements is: 51
+ Hint
Loop through the array. Inside the loop, access the element at index i using the expression *(array_name + i) and add it to a running total.
+ Show Solution
#include <iostream>
int main() {
int arr[] = {1, 5, 10, 15, 20};
int size = sizeof(arr) / sizeof(arr[0]);
int sum = 0;
// The array name 'arr' decays to a pointer to the first element
int* arr_ptr = arr;
for (int i = 0; i < size; ++i) {
// Access element using pointer arithmetic: *(arr_ptr + i)
sum += *(arr_ptr + i);
}
std::cout << "The sum of array elements is: " << sum << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The pointer
arr_ptrholds the base address of the array. The expressionarr_ptr + iperforms scaled pointer arithmetic, calculating the memory address of the element at the current indexi. - The dereference operator (
*) then retrieves the integer value at that address, which is accumulated insum. This explicitly demonstrates how pointers are used to traverse arrays in C++.
Exercise 11: Reverse Array
Problem Statement: Write a program to print the elements of an integer array {1, 2, 3, 4, 5} in reverse order using only pointer notation and arithmetic. You must not use the array index operator ([]).
Given:
int numbers[] = {1, 2, 3, 4, 5};Code language: C++ (cpp)
Expected Output:
Elements in reverse order: 5 4 3 2 1
+ Hint
- Calculate the address of the last element first.
- Use a
whileloop and the decrement operator (--) on the pointer to move backward through the array until the pointer reaches the base address.
+ Show Solution
#include <iostream>
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int size = sizeof(numbers) / sizeof(numbers[0]);
// Pointer to the first element (the base address)
int* start_ptr = numbers;
// Calculate the address of the LAST element: &numbers[size - 1]
int* current_ptr = start_ptr + (size - 1);
std::cout << "Elements in reverse order: ";
// Loop backward while the current pointer is >= the start pointer
while (current_ptr >= start_ptr) {
std::cout << *current_ptr << " ";
current_ptr--; // Decrement the pointer to move to the previous element
}
std::cout << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The pointer
current_ptris initialized to the address of the last array element. Thewhileloop checks that the pointer is still within the array bounds. - The core operation is
current_ptr--, which moves the pointer backward bysizeof(int)bytes, effectively pointing to the memory location of the previous element, allowing the array to be traversed and printed in reverse order.
Exercise 12: Finding Minimum
Problem Statement: Write a function named find_min_ptr that takes an integer array and its size as input, and returns a pointer to the smallest element in that array. In the main function, call this function and use the returned pointer to print the minimum value.
Given:
int data[] = {45, 12, 67, 8, 33};Code language: C++ (cpp)
Expected Output:
The smallest element is: 8
+ Hint
- Initialize your result pointer to point to the first element of the array. Iterate through the array using another pointer (or index).
- Inside the loop, compare the value pointed to by the current element with the value pointed to by your result pointer. If the current element is smaller, update the result pointer.
+ Show Solution
#include <iostream>
// Function that returns a pointer to the smallest integer
int* find_min_ptr(int arr[], int size) {
if (size == 0) {
return nullptr; // Handle empty array case
}
// Initialize the minimum pointer to the first element
int* min_ptr = arr;
for (int i = 1; i < size; ++i) {
// Compare the value pointed to by the current array index (arr[i])
// with the value pointed to by min_ptr (*min_ptr)
if (arr[i] < *min_ptr) {
// Update the pointer to point to the new minimum element
min_ptr = &arr[i];
}
}
return min_ptr;
}
int main() {
int data[] = {45, 12, 67, 8, 33};
int size = sizeof(data) / sizeof(data[0]);
int* min_element_ptr = find_min_ptr(data, size);
if (min_element_ptr != nullptr) {
std::cout << "The smallest element is: " << *min_element_ptr << std::endl;
} else {
std::cout << "The array is empty." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The function
find_min_ptris designed to return anint*. It initializesmin_ptrto the start of the array. Inside the loop, it compares the current element (arr[i]) with the value pointed to bymin_ptr(*min_ptr). - If a smaller value is found,
min_ptris updated using the address-of operator (&) to point to the new minimum element’s location (&arr[i]). - The
mainfunction then dereferences the returned pointer to get the actual minimum value (8).
Exercise 13: 2D Array Traversal
Problem Statement: Declare a small two-dimensional integer array, for example, a 3×3 array initialized with values. Write a program that uses an integer pointer to access and print all elements of the 2D array, treating it as a contiguous block of memory. You must use pointer arithmetic, not standard bracket indexing ([][]).
Given:
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};Code language: C++ (cpp)
Expected Output:
2D Array elements accessed contiguously:
1 2 3
4 5 6
7 8 9
+ Hint
- A 2D array is stored contiguously in memory (row by row). You can treat the array name as a pointer to the first element of the first row.
- Use a single
forloop that runs from 0 up tototal_elements - 1. Access the element at indexiusing*(ptr + i).
+ Show Solution
#include <iostream>
int main() {
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Calculate total elements
const int ROWS = 3;
const int COLS = 3;
const int TOTAL_ELEMENTS = ROWS * COLS;
// The array name 'matrix' can be cast or implicitly converted
// to a pointer to the first element's data type (int*) for contiguous access
int* ptr = (int*)matrix;
std::cout << "2D Array elements accessed contiguously:" << std::endl;
for (int i = 0; i < TOTAL_ELEMENTS; ++i) {
// Access the element using pointer arithmetic
std::cout << *(ptr + i) << " ";
// Add a newline after every row (every 3 elements)
if ((i + 1) % COLS == 0) {
std::cout << std::endl;
}
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The line
int* ptr = (int*)matrix;casts the 2D array’s starting address to a simple integer pointer (int*). - Since the array elements are stored sequentially in memory, we can use a single loop iterating from 0 to 8. In each iteration,
ptr + icalculates the address of the i-th element from the start, and*(ptr + i)retrieves its value. This highlights how multi-dimensional arrays are physically arranged in memory.
Exercise 14: Copying an Array
Problem Statement: Write a function named copy_array that takes three arguments: a destination integer array, a source integer array, and the size of the arrays. The function must use pointers to copy the contents from the source array into the destination array.
Given:
int source[] = {10, 20, 30, 40, 50};Code language: C++ (cpp)
Expected Output:
Destination array contents: 10 20 30 40 50
+ Hint
- Use a single
forloop that iterates over the size. - Inside the loop, you can use either bracket notation with pointers (
dest_ptr[i]) or pure pointer arithmetic (*(dest_ptr + i)) for assignment. The simplest approach is*(destination + i) = *(source + i).
+ Show Solution
#include <iostream>
// Function to copy source array to destination array using pointers
void copy_array(int* dest, const int* src, int size) {
for (int i = 0; i < size; ++i) {
// Copy value from source address to destination address
*(dest + i) = *(src + i);
}
}
int main() {
const int SIZE = 5;
int source[] = {10, 20, 30, 40, 50};
int destination[SIZE]; // Array to receive the copy
copy_array(destination, source, SIZE);
std::cout << "Destination array contents: ";
for (int i = 0; i < SIZE; ++i) {
std::cout << destination[i] << " ";
}
std::cout << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The function parameters are defined as pointers (
int* dest,const int* src), which are the typical way to pass arrays to functions in C++. - The
constkeyword on the source pointer is good practice, indicating that the source data will not be modified. The core logic*(dest + i) = *(src + i);dereferences the i-th element of the source array to get its value, and then assigns that value to the location pointed to by the i-th address of the destination array.
Exercise 15: Comparing Arrays
Problem Statement: Write a function named compare_arrays that takes two integer arrays and their size as input. The function should use pointers to check if the two arrays are identical (i.e., they have the same size and the same elements in the same order). Return true if they are identical, and false otherwise.
Given:
int a1[] = {1, 2, 3, 4};
int a2[] = {1, 2, 3, 4};
int a3[] = {1, 2, 9, 4};Code language: C++ (cpp)
Expected Output:
Array a1 and a2 are identical.
Array a1 and a3 are NOT identical.
+ Hint
- Iterate through the arrays element by element. Use pointer dereference to compare the values at the current addresses:
*ptr1 != *ptr2. - If a mismatch is found at any point, immediately return
false. If the loop completes without finding any differences, returntrue.
+ Show Solution
#include <iostream>
// Function to compare two arrays using pointers
bool compare_arrays(const int* arr1, const int* arr2, int size) {
for (int i = 0; i < size; ++i) {
// Access elements using pointer arithmetic and dereference
if (*(arr1 + i) != *(arr2 + i)) {
return false; // Found a difference
}
}
return true; // No differences found
}
int main() {
const int SIZE = 4;
int a1[] = {1, 2, 3, 4};
int a2[] = {1, 2, 3, 4};
int a3[] = {1, 2, 9, 4};
// Compare a1 and a2 (Identical)
if (compare_arrays(a1, a2, SIZE)) {
std::cout << "Array a1 and a2 are identical." << std::endl;
} else {
std::cout << "Array a1 and a2 are NOT identical." << std::endl;
}
// Compare a1 and a3 (Different)
if (compare_arrays(a1, a3, SIZE)) {
std::cout << "Array a1 and a3 are identical." << std::endl;
} else {
std::cout << "Array a1 and a3 are NOT identical." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- The function
compare_arraystakes constant pointers to ensure the original arrays aren’t accidentally modified. - It loops from i=0 up to
size-1. The checkif (*(arr1 + i) != *(arr2 + i))compares the values at the current memory addresses in both arrays. If the values differ, the function immediately terminates and returnsfalse. - This early exit optimization is efficient. If the loop finishes, it means all elements matched, and
trueis returned.
Exercise 16: Sub-array Printing
Problem Statement: Given an integer array, a starting index (start), and an ending index (end), write a program that uses a pointer to print only the elements in that specific sub-range (inclusive of start, exclusive of end).
Given:
int data[] = {10, 20, 30, 40, 50, 60};
int start_index = 2; // Element 30
int end_index = 5; // Up to element 50 (exclusive)Code language: C++ (cpp)
Expected Output:
Sub-array elements: 30 40 50
+ Hint
- Initialize a pointer to the base address of the array. Calculate the starting pointer for the sub-range using pointer arithmetic:
array_ptr + start. - Loop from this starting pointer until the address equals
array_ptr + end.
+ Show Solution
#include <iostream>
void print_sub_array(int* arr, int start, int end) {
// Calculate the pointer to the start of the sub-range
int* current_ptr = arr + start;
// Calculate the pointer to one element PAST the end of the sub-range
int* end_ptr = arr + end;
std::cout << "Sub-array elements: ";
// Loop while the current pointer has not reached the end pointer
while (current_ptr < end_ptr) {
std::cout << *current_ptr << " ";
current_ptr++;
}
std::cout << std::endl;
}
int main() {
int data[] = {10, 20, 30, 40, 50, 60};
int start_index = 2; // Element 30
int end_index = 5; // Up to element 50 (exclusive)
print_sub_array(data, start_index, end_index); // Expected: 30 40 50
return 0;
}Code language: C++ (cpp)
Explanation:
- The function first calculates the starting and ending addresses for the print range using pointer arithmetic (
arr + startandarr + end). - The
whileloop uses the addresses themselves for the boundary condition (current_ptr < end_ptr). Inside the loop,*current_ptrprints the value, andcurrent_ptr++moves the pointer to the next element. - This technique is common in C++ iterators, where ranges are defined by a starting pointer (or iterator) and an exclusive ending pointer.
Exercise 17: Pass-by-Pointer (Swap)
Problem Statement: Write a function called swap that takes two integer pointers as arguments. The function must swap the values stored in the memory locations that these pointers point to. In main, declare two integers and call swap using their addresses.
Given:
int a = 10;
int b = 20;Code language: C++ (cpp)
Expected Output:
Before swap: a = 10, b = 20
After swap: a = 20, b = 10
+ Hint
- When implementing the swap logic inside the function, you must use the dereference operator (
*) on the pointers to access and modify the actual variables from themainfunction. - Use a temporary variable to hold one value during the swap process.
+ Show Solution
#include <iostream>
// Function to swap the values pointed to by p1 and p2
void swap(int* p1, int* p2) {
int temp = *p1; // Store the value at p1's address
*p1 = *p2; // Assign the value at p2's address to p1's address
*p2 = temp; // Assign the stored value (original p1) to p2's address
}
int main() {
int a = 10;
int b = 20;
std::cout << "Before swap: a = " << a << ", b = " << b << std::endl;
// Pass the addresses of a and b to the function
swap(&a, &b);
std::cout << "After swap: a = " << a << ", b = " << b << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- This is the classic example of pass-by-pointer, which allows a function to modify variables defined in the calling function (
main). Whenswap(&a, &b)is called, the addresses ofaandbare passed. - Inside
swap, the pointersp1andp2hold these addresses. By using the dereference operator (*p1and*p2), the function accesses and changes the values of the variablesaandbdirectly in themainfunction’s memory space.
Exercise 18: Modifying String in Function
Problem Statement: Write a function named to_uppercase that takes a character pointer (char*) representing a C-style string. The function must iterate through the string using pointer arithmetic and modify the characters in place to convert all lowercase letters to uppercase. Use the standard library function toupper() from <cctype>.
Given:
char text[] = "hello pointers exercise";Code language: C++ (cpp)
Expected Output:
Original: hello pointers exercise
Uppercase: HELLO POINTERS EXERCISE
+ Hint
- A C-style string ends with the null-terminator (
\0). - Loop while the character pointed to is not
\0(while (*str_ptr != '\0')). - Inside the loop, use
*str_ptr = toupper(*str_ptr)to modify the character, and then increment the pointer (str_ptr++).
+ Show Solution
#include <iostream>
#include <cctype>
// Function to convert a C-style string to uppercase in place
void to_uppercase(char* str_ptr) {
// Loop until the null-terminator is reached
while (*str_ptr != '\0') {
// Use toupper() to convert the character and assign it back
// to the memory location pointed to by str_ptr
*str_ptr = std::toupper(*str_ptr);
// Move the pointer to the next character
str_ptr++;
}
}
int main() {
// Note: Must be char array, not const char* literal, to allow modification
char text[] = "hello pointers exercise";
std::cout << "Original: " << text << std::endl;
to_uppercase(text);
std::cout << "Uppercase: " << text << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The function
to_uppercaseaccepts the string’s base address viachar* str_ptr. Thewhileloop uses the dereferenced value (*str_ptr) as its condition, ensuring it stops at the null-terminator. - The assignment
*str_ptr = std::toupper(*str_ptr);modifies the character at the current memory location. - Since the function is passed the address of the original array (
text), the changes are permanent and visible inmain. Thestr_ptr++moves the pointer to the next memory address (one byte further).
Exercise 19: Function Pointer Declaration
Problem Statement: Write a simple function add that takes two integers and returns their sum. In main, declare a function pointer that can point to a function with this signature. Assign the add function to this pointer and then call the add function using the function pointer.
Given:
int a = 10;
int b = 5;Code language: C++ (cpp)
Expected Output:
Result 1 (10 + 5): 15
+ Hint
- The syntax for a function pointer is verbose:
return_type (*pointer_name)(parameter_list). - For the
addfunction, the declaration isint (*func_ptr)(int, int);.
+ Show Solution
#include <iostream>
int add(int a, int b) {
return a + b;
}
int main() {
// 1. Declare a function pointer named 'op_ptr'
int (*op_ptr)(int, int);
// 2. Assign the 'add' function's address to the pointer
op_ptr = add;
// 3. Call the function using the pointer (dereference is optional but good practice)
int result1 = op_ptr(10, 5);
int result2 = (*op_ptr)(25, 75); // Equivalent call using explicit dereference
std::cout << "Result 1 (10 + 5): " << result1 << std::endl;
std::cout << "Result 2 (25 + 75): " << result2 << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The line
int (*op_ptr)(int, int);declaresop_ptras a pointer that can store the address of any function that takes twoints and returns anint. - Assignment is simple:
op_ptr = add;(the function name decays to its address). - Calling the function via the pointer (
op_ptr(10, 5)) is virtually identical to calling the function directly. Function pointers are essential for implementing callback functions and designing flexible interfaces.
Exercise 20: Callback Function
Problem Statement: Define two simple functions: multiply(int, int) and subtract(int, int). Write a function called compute_result that takes three arguments: two integers and a function pointer (which must match the signature of multiply or subtract). Inside compute_result, use the function pointer to perform the operation on the two integers and return the result. Use compute_result to call both multiply and subtract.
Given:
int x = 50;
int y = 10;Code language: C++ (cpp)
Expected Output:
Multiplication result: 500
Subtraction result: 40
+ Hint
- The
compute_resultfunction must accept the function pointer as one of its parameters. - You can call the pointed-to function directly within
compute_resultusing the function pointer’s name and arguments.
+ Show Solution
#include <iostream>
// Type definition for easier readability of the function pointer signature
typedef int (*OperationPtr)(int, int);
int multiply(int a, int b) {
return a * b;
}
int subtract(int a, int b) {
return a - b;
}
// Function that takes a function pointer (callback) as an argument
int compute_result(int val1, int val2, OperationPtr operation) {
// Call the function pointed to by 'operation'
return operation(val1, val2);
}
int main() {
int x = 50;
int y = 10;
// Pass the multiply function's address (decayed name)
int product = compute_result(x, y, multiply);
std::cout << "Multiplication result: " << product << std::endl;
// Pass the subtract function's address (decayed name)
int difference = compute_result(x, y, subtract);
std::cout << "Subtraction result: " << difference << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The
typedefmakes the function pointer signature more readable. Thecompute_resultfunction is designed as a generic interface. It doesn’t know which operation it will perform until runtime. - When called, the
multiplyorsubtractfunction’s address is passed. Insidecompute_result, the linereturn operation(val1, val2);executes the function currently pointed to byoperation. - This pattern is known as a callback and allows for highly flexible and extensible code design.
Exercise 21: Pointer to Constant Data
Problem Statement: Write a function named print_constant_value that accepts a pointer to a constant integer (const int*). Inside the function, print the value pointed to. In main, attempt to call the function and then try to use the pointer inside the function to modify the pointed-to value. Observe and explain the resulting compilation error.
Given:
int data = 100;Code language: C++ (cpp)
Expected Output:
Value via const pointer: 100
Value via const pointer: 200
+ Hint
The declaration const int* ptr; means the pointer can change (point to something else), but the data it points to cannot be changed through this pointer. The compiler enforces this protection.
+ Show Solution
#include <iostream>
// Function accepts a pointer to constant data
void print_constant_value(const int* ptr) {
if (ptr != nullptr) {
std::cout << "Value via const pointer: " << *ptr << std::endl;
// ** Attempting to modify the value here will cause a compile error **
// *ptr = 500;
// Uncommenting the line above results in:
// error: assignment of read-only location ‘*ptr’
}
}
int main() {
int data = 100;
// The pointer itself is not constant, but the data is treated as such
print_constant_value(&data);
// We can still modify 'data' directly because it's not constant
data = 200;
print_constant_value(&data);
return 0;
}Code language: C++ (cpp)
Explanation:
- The function signature
const int* ptrdeclares a pointer to constant data. This means that although the variabledatainmainis not constant, the function guarantees it will treat the data pointed to byptras read-only. - This is a crucial safety mechanism: it allows the function to read data without the risk of accidental modification. The compiler prevents the assignment
*ptr = 500because it violates theconstcontract specified in the function parameter.
Exercise 22: Constant Pointer
Problem Statement: Declare an integer variable x initialized to 5. Declare a constant pointer to an integer (int* const) named const_ptr and initialize it to point to x. Use the pointer to successfully change the value of x to 10. Then, declare a second integer y and attempt to make const_ptr point to y. Observe and explain the resulting compilation error.
Given:
int x = 5;
int y = 25;Code language: C++ (cpp)
Expected Output:
x after modification via pointer: 10
+ Hint
- The declaration
int* const ptr;means the pointer must always point to the same memory location, but the value at that location can be changed. - The
constapplies to the pointer variable itself, preventing its address from being reassigned.
+ Show Solution
#include <iostream>
int main() {
int x = 5;
int y = 25;
// Constant pointer: must always point to the address of 'x'
int* const const_ptr = &x;
// 1. SUCCESS: We can modify the data 'x' via the pointer
*const_ptr = 10;
std::cout << "x after modification via pointer: " << x << std::endl; // Prints 10
// 2. FAILURE: Attempting to change the pointer itself
// const_ptr = &y;
// Uncommenting the line above results in:
// error: assignment of read-only variable ‘const_ptr’
return 0;
}Code language: C++ (cpp)
Explanation:
- The declaration
int* const const_ptr = &x;defines a constant pointer. Theconstmodifier is placed after the asterisk, making the pointer address itself immutable. - Thus, the pointer must always point to the address of
xand cannot be reassigned to point toy. However, since the data type (int) is not constant, the value at the address (i.e.,x) can be freely changed using the dereference operator (*const_ptr = 10).
Exercise 23: Pointer to Struct
Problem Statement: Define a structure named Rectangle with two integer members: length and width. Declare a Rectangle variable, initialize its members, and then declare a pointer to that structure. Access and modify the structure members using the arrow operator (->). Print the final dimensions.
Expected Output:
Original dimensions: 10 x 5
New dimensions: 15 x 7
+ Hint
- The arrow operator (
->) is a shorthand in C++ specifically designed for pointers to structures or classes. - It combines the dereference operator and the member access operator:
ptr->memberis equivalent to(*ptr).member.
+ Show Solution
#include <iostream>
struct Rectangle {
int length;
int width;
};
int main() {
Rectangle rect = {10, 5};
// Declare and initialize a pointer to the structure
Rectangle* rect_ptr = ▭
std::cout << "Original dimensions: " << rect_ptr->length
<< " x " << rect_ptr->width << std::endl;
// Modify members using the arrow operator
rect_ptr->length = 15;
rect_ptr->width = 7;
std::cout << "New dimensions: " << rect.length
<< " x " << rect.width << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The line
Rectangle* rect_ptr = ▭sets up the structure pointer. - The arrow operator (
->) is used to access members through the pointer, such asrect_ptr->length. This operator automatically dereferences the pointer and accesses the specified member, making code much cleaner than using the verbose(*rect_ptr).lengthsyntax. - This is fundamental when working with linked lists or dynamic objects in C++
Exercise 24: Dynamic Allocation (Single Variable)
Problem Statement: Use the new operator to dynamically allocate memory for a single float variable on the heap. Store the address in a float pointer. Initialize the allocated memory to the value 3.14. Print the value, and then use the delete operator to deallocate the memory.
Sample Output:
Dynamically allocated float value: 3.14
Address on heap: 0x61499874f920
+ Hint
- Dynamic allocation uses
new Type. Deallocation usesdelete pointer. - Failing to use
deleteresults in a memory leak. Always check if the pointer is notnullptrafter allocation (thoughnewthrows an exception by default if allocation fails).
+ Show Solution
#include <iostream>
int main() {
// Dynamically allocate a single float on the heap
float* float_ptr = new float;
// Check if allocation was successful (optional but good practice)
if (float_ptr == nullptr) {
std::cerr << "Memory allocation failed!" << std::endl;
return 1;
}
// Initialize the allocated memory
*float_ptr = 3.14f;
std::cout << "Dynamically allocated float value: " << *float_ptr << std::endl;
std::cout << "Address on heap: " << float_ptr << std::endl;
// Deallocate the memory to prevent memory leak
delete float_ptr;
// Set the pointer to nullptr after deletion to avoid dangling pointer issues
float_ptr = nullptr;
return 0;
}Code language: C++ (cpp)
Explanation:
- The statement
float* float_ptr = new float;allocates enough memory on the heap to hold a singlefloatand stores the starting address infloat_ptr. - The value is set using dereference:
*float_ptr = 3.14f;. Crucially,delete float_ptr;returns the allocated memory back to the system, preventing a memory leak. - Setting the pointer to
nullptrafter deletion is important to avoid a dangling pointer—a pointer that still holds the address of deallocated memory.
Exercise 25: Dynamic Allocation (Array)
Problem Statement: Use the new[] operator to dynamically allocate an integer array of size 8. Use a pointer to fill the array with the values 10, 20, 30, …, 80. Print all values using pointer arithmetic traversal. Finally, use the delete[] operator to correctly deallocate the entire array.
Expected Output:
Dynamically allocated array: 10 20 30 40 50 60 70 80
+ Hint
- To allocate an array, use
new Type[size]. - To deallocate the array, you must use the array form of delete:
delete[] pointer. Usingdelete pointeron an array leads to undefined behavior.
+ Show Solution
#include <iostream>
int main() {
const int SIZE = 8;
// Dynamically allocate an array of 8 integers on the heap
int* array_ptr = new int[SIZE];
// Fill the array using pointer arithmetic
for (int i = 0; i < SIZE; ++i) {
*(array_ptr + i) = (i + 1) * 10;
}
// Print the array using pointer traversal
std::cout << "Dynamically allocated array: ";
for (int i = 0; i < SIZE; ++i) {
std::cout << array_ptr[i] << " "; // Using [] is fine after allocation
}
std::cout << std::endl;
// Crucial step: Deallocate the entire array
delete[] array_ptr;
array_ptr = nullptr;
return 0;
}Code language: C++ (cpp)
Explanation:
- The statement
int* array_ptr = new int[SIZE];allocates a contiguous block of memory large enough for 8 integers. - We then treat
array_ptrjust like a regular array name. The loop fills the elements using pointer arithmetic. The commanddelete[] array_ptr;is mandatory for arrays. - The square brackets inform the C++ runtime that it needs to run destructors (if applicable) and deallocate the entire contiguous block, not just the memory for the first element.
Exercise 26: Array of Pointers
Problem Statement: Declare five individual integer variables (e.g., n1, n2, …). Declare an array of 5 integer pointers (int* array_of_ptrs[5]). Make each element in the array of pointers point to one of the five individual integer variables. Use the array of pointers to print all five integer values.
Given:
int n1 = 10;
int n2 = 20;
int n3 = 30;
int n4 = 40;
int n5 = 50;Code language: C++ (cpp)
Expected Output:
Values via array of pointers: 10 20 30 40 50
+ Hint
The array stores addresses. You must use both the index operator ([]) to select the pointer from the array and the dereference operator (*) to get the value at the pointed-to address. For example: *array_of_ptrs[i].
+ Show Solution
#include <iostream>
int main() {
int n1 = 10;
int n2 = 20;
int n3 = 30;
int n4 = 40;
int n5 = 50;
// Declare an array of 5 integer pointers
int* array_of_ptrs[5];
// Assign the address of each integer to an element in the pointer array
array_of_ptrs[0] = &n1;
array_of_ptrs[1] = &n2;
array_of_ptrs[2] = &n3;
array_of_ptrs[3] = &n4;
array_of_ptrs[4] = &n5;
std::cout << "Values via array of pointers: ";
for (int i = 0; i < 5; ++i) {
// Dereference the pointer stored at index i
std::cout << *array_of_ptrs[i] << " ";
}
std::cout << std::endl;
return 0;
}Code language: C++ (cpp)
Explanation:
- The declaration
int* array_of_ptrs[5];creates an array on the stack where each of the five slots is designed to hold a memory address (anint*). - We populate this array with the addresses of the five stack variables. In the loop,
array_of_ptrs[i]retrieves the stored address, and the leading*operator retrieves the value from that address. This structure is often used to manage a collection of scattered data efficiently.
Exercise 27: Finding a Substring
Problem Statement: Write a function named find_first_occurrence that mimics a simplified strstr. It takes two char pointers: a source string and a target string (substring). It should search for the first occurrence of the target substring within the source string. If found, the function must return a pointer to the starting character of the match within the source string. If not found, return nullptr.
Given:
const char* main_str = "programming in c++ is fun";
const char* sub_str = "c++";Code language: C++ (cpp)
Expected Output:
Substring found starting at: c++ is fun
Source string starting from match: c++ is fun
+ Hint
- This requires nested loops. The outer loop traverses the
sourcestring. - The inner loop compares characters from the current position in
sourcewith the characters intarget. If all characters match until thetarget‘s null terminator, return the currentsourcepointer.
+ Show Solution
#include <iostream>
// Returns a pointer to the first occurrence of target in source, or nullptr
char* find_first_occurrence(const char* source, const char* target) {
if (*target == '\0') return (char*)source; // Empty target is a special case
const char* current_source = source;
// Outer loop: Iterate through the source string
while (*current_source != '\0') {
const char* s = current_source;
const char* t = target;
// Inner loop: Compare characters from current position
while (*t != '\0' && *s == *t) {
s++;
t++;
}
// Check if the inner loop reached the end of the target string
if (*t == '\0') {
return (char*)current_source; // Match found, return the start address
}
current_source++; // Move to the next character in the source
}
return nullptr; // No match found
}
int main() {
const char* main_str = "programming in c++ is fun";
const char* sub_str = "c++";
char* found_ptr = find_first_occurrence(main_str, sub_str);
if (found_ptr != nullptr) {
std::cout << "Substring found starting at: " << found_ptr << std::endl;
std::cout << "Source string starting from match: " << found_ptr << std::endl;
} else {
std::cout << "Substring not found." << std::endl;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This function uses multiple pointers to manage the search.
current_sourcetracks the starting point in the main string. - The inner pointers (
sandt) perform the character-by-character comparison. If the innerwhileloop completes because*thit the null-terminator (\0), it means a full match was found. - The function then returns
current_source, the address where the match began. If the outer loop finishes, the function returnsnullptr, indicating no match.
Exercise 28: Memory Leak Demonstration
Problem Statement: Write a function named leak_memory that contains a simple for loop that runs 100 times. Inside the loop, use new int to dynamically allocate memory for an integer, but do not use delete. In main, call this function and explain why this pattern leads to a memory leak. (Note: Running this in a real scenario will increase memory usage, but for the exercise, just understand the mechanism).
+ Hint
- A memory leak occurs when a program loses the only pointer to a dynamically allocated block of memory before that memory is deallocated.
- Once the function finishes, the local pointer goes out of scope, and the memory becomes inaccessible.
+ Show Solution
Explanation:
- Inside the loop,
int* temp_ptr = new int(i);allocates a block of heap memory. - When the loop iterates to the next cycle, the local variable
temp_ptris destroyed (it goes out of scope). However, the memory block it pointed to on the heap remains allocated. - Since
temp_ptrwas the only variable holding the address of that block, the program has lost the ability to calldelete. - This inaccessible memory is a memory leak, reducing the available memory until the program terminates and the operating system automatically reclaims it.
Exercise 29: Reallocation Simulation
Problem Statement: Dynamically allocate a small integer array (size 5) and initialize it. Write a function named resize_array that simulates reallocation by: 1) creating a new, larger array (size 10) on the heap, 2) using pointers to copy the contents of the old array to the new array, and 3) correctly deleting the old array. Return the pointer to the new array.
Given:
int old_size = 5;
int new_size = 10;Code language: C++ (cpp)
Expected Output:
Original array (size 5): 1 2 3 4 5
Resized array (size 10): 1 2 3 4 5 99 99 99 99 99
+ Hint
The function must accept a pointer to the old array. After copying, use delete[] on the old pointer before returning the new pointer.
+ Show Solution
#include <iostream>
// Returns a pointer to the new array, requires size updates in calling code
int* resize_array(int* old_array, int old_size, int new_size) {
// 1. Create a new, larger array
int* new_array = new int[new_size];
// 2. Copy contents from old array to new array using pointers
for (int i = 0; i < old_size; ++i) {
*(new_array + i) = *(old_array + i);
}
// 3. Clean up the old array memory
delete[] old_array;
return new_array;
}
int main() {
int old_size = 5;
int new_size = 10;
// Initial dynamic allocation
int* data_ptr = new int[old_size]{1, 2, 3, 4, 5};
std::cout << "Original array (size 5): ";
for (int i = 0; i < old_size; ++i) std::cout << data_ptr[i] << " ";
std::cout << std::endl;
// Simulate reallocation
data_ptr = resize_array(data_ptr, old_size, new_size);
old_size = new_size; // Update size tracking variable
// The new array has copied data and new uninitialized space
std::cout << "Resized array (size 10): ";
for (int i = 0; i < old_size; ++i) {
std::cout << (data_ptr[i] == 0 ? 99 : data_ptr[i]) << " "; // Print 99 for uninitialized
}
std::cout << std::endl;
delete[] data_ptr;
return 0;
}Code language: C++ (cpp)
Explanation:
- C++ does not have a built-in
realloclike C. This function demonstrates the manual process: allocate new memory (new int[new_size]), copy data, and deallocate old memory (delete[] old_array). - The key challenge is ensuring the old pointer is correctly deleted, and the new pointer (the base address of the larger block) is correctly returned and used to update the pointer variable (
data_ptr) inmain. - This is the fundamental mechanism behind C++ container classes like
std::vectorwhen they grow in size.
Exercise 30: Linked List Node (Concept)
Problem Statement: Define a simple structure named Node containing an integer data member and a pointer named next that points to another Node structure (i.e., Node* next). Create three such nodes dynamically (n1, n2, n3). Link them sequentially using the next pointer (n1 -> n2 -> n3). Finally, traverse the small list using a temporary pointer and print all the data values.
Expected Output:
Linked List Traversal: 10 20 30
+ Hint
- The declaration
Node* next;is a self-referential structure, the basis of a linked list. - To link n1 to n2, you set
n1.next = &n2;. The traversal starts at the head and continueswhile (temp_ptr != nullptr).
+ Show Solution
#include <iostream>
struct Node {
int data;
Node* next; // Pointer to the next node in the list
};
int main() {
// 1. Create three nodes dynamically
Node* n1 = new Node{10, nullptr};
Node* n2 = new Node{20, nullptr};
Node* n3 = new Node{30, nullptr};
// 2. Link them sequentially
n1->next = n2; // n1 points to n2
n2->next = n3; // n2 points to n3
// n3->next is already nullptr
// 3. Traverse the list starting from the head (n1)
Node* current = n1;
std::cout << "Linked List Traversal: ";
while (current != nullptr) {
std::cout << current->data << " ";
current = current->next; // Move to the next node using the pointer
}
std::cout << std::endl;
// 4. Clean up (essential for dynamic structures)
current = n1;
while (current != nullptr) {
Node* next_node = current->next;
delete current;
current = next_node;
}
return 0;
}Code language: C++ (cpp)
Explanation:
- This exercise demonstrates the core concept of a linked list, which relies entirely on pointers. The
Nodestructure is self-referential because it contains a pointer to its own type. - The links are established by setting the
nextpointer of one node to the address of the subsequent node (e.g.,n1->next = n2;). Traversal starts at thehead(n1) and moves forward by continually updating thecurrentpointer to the value stored incurrent->next. - The cleanup phase is critical: memory must be deallocated node by node to avoid leaks.

Leave a Reply