Advanced Pointers in C

Pointers are far more versatile than just storing the address of a variable. C allows pointers to point to functions, arrays, strings, and even other pointers. Understanding advanced pointer concepts is key to writing flexible, powerful C programs and understanding how things like callbacks, generic functions, and dynamic dispatch work.

Pointer to an Array

A pointer to an array points to the entire array as a unit, not just the first element.


#include <stdio.h>

int main() {
    int arr[5] = {10, 20, 30, 40, 50};

    int *ptr  = arr;           // pointer to first element
    int (*aptr)[5] = &arr;    // pointer to the entire array of 5 ints

    printf("Using ptr (element pointer):\n");
    for (int i = 0; i < 5; i++)
        printf("%d ", *(ptr + i));

    printf("\nFirst element via array pointer: %d\n", (*aptr)[0]);
    printf("Third element via array pointer: %d\n", (*aptr)[2]);

    return 0;
}

Output


Using ptr (element pointer):
10 20 30 40 50 
First element via array pointer: 10
Third element via array pointer: 30

Array of Pointers

An array where each element is a pointer. Very commonly used to hold an array of strings.


#include <stdio.h>

int main() {
    // Array of pointer to string literals
    char *fruits[] = {"Apple", "Banana", "Mango", "Orange"};
    int n = 4;

    for (int i = 0; i < n; i++)
        printf("fruits[%d] = %s\n", i, fruits[i]);

    return 0;
}

Output


fruits[0] = Apple
fruits[1] = Banana
fruits[2] = Mango
fruits[3] = Orange

Array of Pointers to Integers


#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 30;
    int *ptrs[3] = {&a, &b, &c};

    for (int i = 0; i < 3; i++)
        printf("Value %d: %d\n", i + 1, *ptrs[i]);

    return 0;
}

Output


Value 1: 10
Value 2: 20
Value 3: 30

Function Pointers

A function pointer stores the address of a function. Just like a variable pointer points to data, a function pointer points to executable code. This allows passing functions as arguments, building callback systems, and creating dispatch tables.

Syntax


return_type (*pointer_name)(parameter_types);

Basic Example


#include <stdio.h>

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }

int main() {
    int (*operate)(int, int);   // function pointer declaration

    operate = add;
    printf("add(10, 3) = %d\n", operate(10, 3));

    operate = sub;
    printf("sub(10, 3) = %d\n", operate(10, 3));

    operate = mul;
    printf("mul(10, 3) = %d\n", operate(10, 3));

    return 0;
}

Output


add(10, 3) = 13
sub(10, 3) = 7
mul(10, 3) = 30

Passing a Function Pointer to Another Function (Callback)


#include <stdio.h>

int square(int n)  { return n * n; }
int doubleIt(int n){ return n * 2; }

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

int main() {
    int nums[] = {1, 2, 3, 4, 5};

    printf("Squares  : ");
    applyToAll(nums, 5, square);

    printf("Doubled  : ");
    applyToAll(nums, 5, doubleIt);

    return 0;
}

Output


Squares  : 1 4 9 16 25 
Doubled  : 2 4 6 8 10 

Dispatch Table Using Function Pointer Array


#include <stdio.h>

float add(float a, float b) { return a + b; }
float sub(float a, float b) { return a - b; }
float mul(float a, float b) { return a * b; }
float dvd(float a, float b) { return (b != 0) ? a / b : 0; }

int main() {
    float (*ops[4])(float, float) = {add, sub, mul, dvd};
    char *names[] = {"+", "-", "*", "/"};

    float x = 12, y = 4;
    for (int i = 0; i < 4; i++)
        printf("%.0f %s %.0f = %.2f\n", x, names[i], y, ops[i](x, y));

    return 0;
}

Output


12 + 4 = 16.00
12 - 4 = 8.00
12 * 4 = 48.00
12 / 4 = 3.00

void Pointer (Generic Pointer)

A void * pointer is a generic pointer that can hold the address of any data type without type specification. It cannot be dereferenced directly — it must be cast to a specific type first. It is used when writing generic functions that work with any data type.


#include <stdio.h>

void printValue(void *ptr, char type) {
    switch (type) {
        case 'i': printf("Integer: %d\n",   *(int *)ptr);   break;
        case 'f': printf("Float:   %.2f\n", *(float *)ptr); break;
        case 'c': printf("Char:    %c\n",   *(char *)ptr);  break;
    }
}

int main() {
    int   num  = 42;
    float price = 9.99;
    char  grade = 'A';

    printValue(&num,   'i');
    printValue(&price, 'f');
    printValue(&grade, 'c');

    return 0;
}

Output


Integer: 42
Float:   9.99
Char:    A

const Pointers

The const keyword can be used with pointers in two ways:

1. Pointer to Constant — cannot change the value it points to


int value = 10;
const int *ptr = &value;
// *ptr = 20;  // ERROR — cannot modify value through this pointer
ptr = &value;  // OK — can change where pointer points

2. Constant Pointer — cannot change where it points


int a = 5, b = 10;
int * const ptr = &a;
*ptr = 99;   // OK — can modify the value
// ptr = &b; // ERROR — cannot point to a different variable

3. Constant Pointer to Constant — cannot change either


const int * const ptr = &a;
// *ptr = 99;  // ERROR
// ptr = &b;  // ERROR

Pointer and String Operations


#include <stdio.h>

int strLen(const char *s) {
    int count = 0;
    while (*s != '\0') { count++; s++; }
    return count;
}

void reverseStr(char *s) {
    char *start = s;
    char *end   = s;
    while (*end) end++;
    end--;
    while (start < end) {
        char tmp = *start;
        *start++ = *end;
        *end--   = tmp;
    }
}

int main() {
    char word[] = "Pointer";
    printf("Length  : %d\n", strLen(word));

    reverseStr(word);
    printf("Reversed: %s\n", word);

    return 0;
}

Output


Length  : 7
Reversed: retniop

Common Pointer Pitfalls

PitfallWhat HappensPrevention
Wild PointerUninitialized pointer used — undefined behaviorAlways initialize: int *p = NULL;
NULL DereferenceAccessing value via NULL pointer — program crashesCheck if (ptr != NULL) before dereferencing
Dangling PointerPointer still points to freed/out-of-scope memorySet ptr = NULL after free(ptr)
Memory LeakAllocated memory never freed — program slowly consumes RAMAlways call free() for every malloc()
Buffer OverflowWriting past array bounds — corrupts memoryAlways track array sizes and stay within bounds

Summary of Pointer Types

TypeDeclarationUse Case
Basic pointerint *pPoint to a single variable
Pointer to arrayint (*p)[5]Point to a whole array
Array of pointersint *p[5]Array of addresses
Function pointerint (*p)(int, int)Point to a function
void pointervoid *pGeneric pointer, any type
Pointer to pointerint **pPoint to another pointer
const pointerconst int *pRead-only access via pointer

Summary

Advanced pointer concepts unlock the real power of C. Pointers to arrays and arrays of pointers are the foundation of multi-dimensional data and string tables. Function pointers enable callback-driven designs and runtime polymorphism. Void pointers allow writing generic functions that work with any data type. Understanding these concepts deeply is what separates a C beginner from a proficient systems programmer.

Leave a Comment

Your email address will not be published. Required fields are marked *