SrcForge

Lesson 37

Advanced Pointers

Advanced Pointers in C build upon basic pointers by introducing pointer to pointer, pointer arithmetic, function pointers, void pointers, and pointers to arrays. These concepts enable flexible, efficient, and reusable programs used in operating systems, embedded systems, dynamic memory management, and callback-driven APIs.

C Track

Save progress as you learn.

44 lessons

Lesson content

Advanced Pointers in C Programming: A Complete Beginner to Advanced Guide

What are Advanced Pointers in C Programming?

Advanced Pointers in C programming build upon the basics of pointers by introducing more powerful techniques such as pointer to pointer, pointer arithmetic, function pointers, void pointers, and pointers to arrays. These concepts allow you to write flexible, efficient, and reusable programs.

Think of a pointer as a house address. A pointer to a pointer is the address of the paper where that house address is written. Similarly, a function pointer is like storing the address of a function so you can call it later.

Why Do Advanced Pointers Exist?

Simple pointers are useful for accessing variables, but larger programs often need more flexibility. Advanced pointer techniques make it possible to modify pointers inside functions, pass functions as arguments, build dynamic data structures, manage memory efficiently, and write reusable libraries.

Real-World Use Cases

Advanced pointers are widely used in:

  • Operating systems
  • Embedded systems
  • Memory management
  • Linked lists
  • Trees and graphs
  • Callback functions
  • Device drivers
  • Standard C libraries
  • Dynamic memory allocation

Prerequisites

Before learning Advanced Pointers in C, you should know:

  • Variables
  • Data types
  • Functions
  • Arrays
  • Basic pointers
  • Address (&) and dereference (*) operators
  • Dynamic memory allocation with malloc() and free() (helpful but optional)

Core Concepts

Pointer to Pointer

A pointer to a pointer stores the address of another pointer.

Syntax

data_type **pointer_name;
int value = 10;
int *ptr = &value;
int **pptr = &ptr;

Pointer Arithmetic

Pointers can move through contiguous memory locations. Supported operations include increment (ptr++), decrement (ptr--), addition (ptr + n), subtraction (ptr - n), and difference between two pointers within the same array.

int arr[] = {10, 20, 30};

int *ptr = arr;

ptr++;

Note: Pointer arithmetic should only be performed within the bounds of the same array.

Void Pointer

A void pointer (void *) is a generic pointer that can hold the address of any data type. A void pointer cannot be dereferenced directly.

int number = 50;

void *ptr = &number;

printf("%d", *(int *)ptr);

Function Pointer

A function pointer stores the address of a function.

Syntax

return_type (*pointer_name)(parameters);
int add(int a, int b);

int (*funcPtr)(int, int) = add;

Pointer to an Array

A pointer can point to an entire array instead of a single element. This differs from a pointer to the first element of an array.

int arr[5];

int (*ptr)[5] = &arr;   // Points to the whole array

int *ptr2 = arr;        // Points to the first element

Code Examples

Example 1: Beginner – Pointer to Pointer

#include <stdio.h>                         // Include standard input/output library

int main()
{
    int number = 100;                      // Declare an integer variable

    int *ptr = &number;                    // Pointer to the integer

    int **pptr = &ptr;                     // Pointer to the pointer

    printf("%d\n", **pptr);                // Access the value through two levels of indirection

    return 0;                              // End program
}

Output: 100

Example 2: Beginner – Pointer Arithmetic

#include <stdio.h>                         // Include standard input/output library

int main()
{
    int numbers[] = {10, 20, 30, 40};      // Declare an integer array

    int *ptr = numbers;                    // Point to the first element

    printf("%d\n", *ptr);                  // Print the first element

    ptr++;                                 // Move to the next element

    printf("%d\n", *ptr);                  // Print the second element

    return 0;                              // End program
}

Output: 10 / 20

Example 3: Intermediate – Void Pointer

#include <stdio.h>                         // Include standard input/output library

int main()
{
    int number = 75;                       // Declare an integer

    void *ptr = &number;                   // Store its address in a void pointer

    printf("%d\n", *(int *)ptr);           // Cast the void pointer before dereferencing

    return 0;                              // End program
}

Output: 75

Example 4: Intermediate – Function Pointer

#include <stdio.h>                                  // Include standard input/output library

int multiply(int a, int b)                          // Function definition
{
    return a * b;                                   // Return the product
}

int main()
{
    int (*operation)(int, int) = multiply;          // Store function address

    printf("%d\n", operation(6, 7));                // Call function through pointer

    return 0;                                       // End program
}

Output: 42

Example 5: Advanced – Callback Using Function Pointer

#include <stdio.h>                                              // Include standard input/output library

int add(int a, int b)                                           // Addition function
{
    return a + b;                                               // Return sum
}

int subtract(int a, int b)                                      // Subtraction function
{
    return a - b;                                               // Return difference
}

void calculate(int a, int b, int (*operation)(int, int))        // Callback function
{
    printf("Result = %d\n", operation(a, b));                   // Execute selected operation
}

int main()
{
    calculate(10, 5, add);                                      // Call using add function

    calculate(10, 5, subtract);                                 // Call using subtract function

    return 0;                                                    // End program
}

Output: Result = 15 / Result = 5

Common Mistakes and Pitfalls

WrongCorrect
void *ptr; printf("%d", *ptr);printf("%d", *(int *)ptr);
Incrementing a pointer beyond the arrayStay within array bounds
Forgetting to initialize a pointerInitialize it before use
Using an invalid function pointerAssign it to a valid function before calling
Dereferencing a NULL pointerCheck for NULL before dereferencing

Wrong:

void *ptr = &value;

printf("%d", *ptr);

Correct:

void *ptr = &value;

printf("%d", *(int *)ptr);

Wrong:

int *ptr;

printf("%d", *ptr);

Correct:

int value = 50;

int *ptr = &value;

printf("%d", *ptr);

Best Practices

  • Initialize pointers before using them.
  • Check pointers for NULL before dereferencing.
  • Keep pointer arithmetic within array bounds.
  • Use const pointers when data should not be modified.
  • Free dynamically allocated memory after use.
  • Use function pointers to implement callbacks and flexible APIs.
  • Avoid unnecessary pointer complexity that reduces readability.
  • Add comments when multiple levels of indirection are involved.

When NOT to Use This

Avoid advanced pointer techniques when:

  • A simple variable or array solves the problem.
  • Readability is more important than flexibility.
  • Team members are unfamiliar with complex pointer syntax.
  • Pointer arithmetic makes the code difficult to maintain.
  • Function pointers are unnecessary and direct function calls are sufficient.

Summary / Key Takeaways

  • Advanced Pointers in C programming provide greater flexibility for managing memory and functions.
  • A pointer to a pointer stores the address of another pointer.
  • Pointer arithmetic allows movement through contiguous memory, such as arrays.
  • A void pointer can point to any data type but must be cast before dereferencing.
  • Function pointers enable callbacks and dynamic function selection.
  • A pointer to an array differs from a pointer to the first array element.
  • Always initialize pointers and check for NULL before dereferencing.
  • Use advanced pointers only when they improve clarity, flexibility, or performance.

FAQ About Advanced Pointers in C

1. What is a pointer to a pointer in C?

A pointer to a pointer stores the address of another pointer. It is commonly used when a function needs to modify a pointer passed by the caller or when working with dynamically allocated multidimensional data.

2. What is a void pointer?

A void * is a generic pointer that can store the address of any data type. It must be cast to the appropriate pointer type before accessing the data it points to.

3. What are function pointers used for?

Function pointers are used to call functions indirectly. They are commonly used for callbacks, event handlers, state machines, and implementing flexible APIs.

4. Is pointer arithmetic safe?

Pointer arithmetic is safe only when performed within the bounds of the same array. Moving a pointer outside the array results in undefined behavior if it is dereferenced.

5. What is the difference between int *ptr and int (*ptr)[5]?

int *ptr points to a single integer or the first element of an array. int (*ptr)[5] points to an entire array of five integers. These pointer types are different and are used for different programming scenarios.