Pointers in C – A Complete Guide with Examples

A pointer is a variable that holds a memory address. This single idea — that a variable can store where data lives rather than the data itself — is what makes C capable of things most languages cannot do cleanly: passing large structures without copying them, building linked lists and trees, writing to hardware registers directly, and allocating memory at runtime. This guide builds from the ground up, with a working example at every step.

What Is a Pointer?

Every variable in C occupies memory. A pointer stores the address of that memory.

#include <stdio.h>

int main(void)
{
    int  x   = 42;
    int *ptr = &x;   /* ptr holds the address of x */

    printf("Value of x:       %d\n",  x);
    printf("Address of x:     %p\n",  (void *)&x);
    printf("ptr holds:        %p\n",  (void *)ptr);
    printf("Value at ptr (*): %d\n",  *ptr);

    return 0;
}
Value of x:       42
Address of x:     0x7ffd3a2b4c1c
ptr holds:        0x7ffd3a2b4c1c
Value at ptr (*): 42

Two operators do all the work:

  • &xaddress-of: returns the address where x lives in memory
  • *ptrdereference: follows the address and gives you the value stored there

Declaring Pointers

int    *pi;   /* pointer to int    */
char   *pc;   /* pointer to char   */
double *pd;   /* pointer to double */
void   *pv;   /* pointer to anything (generic) */

The * is part of the variable name, not the type. int *a, b; declares a as a pointer and b as a plain int. Write int *a, *b; if you want two pointers.

Always initialise a pointer before using it. An uninitialised pointer holds garbage and dereferencing it is undefined behaviour. Use NULL to mark a pointer as not yet pointing anywhere:

int *p = NULL;
if (p != NULL)
    printf("%d\n", *p);  /* safe — only dereferences when not NULL */

Modifying a Variable Through a Pointer

Assigning through a dereference changes the original variable:

#include <stdio.h>

int main(void)
{
    int  x   = 10;
    int *ptr = &x;

    *ptr = 99;  /* changes x through the pointer */

    printf("x is now: %d\n", x);  /* 99 */
    return 0;
}
x is now: 99

Pointers and Functions — Pass by Reference

C passes function arguments by value. To let a function modify a caller’s variable, pass its address:

#include <stdio.h>

void swap(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

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

This is how scanf works — scanf("%d", &x) passes the address of x so the function can write into it.

Pointers and Arrays

An array name decays to a pointer to its first element. Pointer arithmetic lets you walk the array without subscripts:

#include <stdio.h>

int main(void)
{
    int arr[] = {10, 20, 30, 40, 50};
    int *p = arr;   /* same as &arr[0] */
    int i;

    for (i = 0; i < 5; i++)
        printf("arr[%d] = %d\n", i, *(p + i));

    return 0;
}
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50

p + i advances the pointer by i elements — not by i bytes. The compiler multiplies by sizeof(int) automatically. This is pointer arithmetic.

Pointer Arithmetic

#include <stdio.h>

int main(void)
{
    int  arr[] = {1, 2, 3, 4, 5};
    int *p = arr;
    int *q = arr + 4;   /* points to last element */

    printf("p points to: %d\n",  *p);
    printf("q points to: %d\n",  *q);
    printf("q - p = %td\n",      q - p);  /* 4: elements between them */

    p++;        /* advance to arr[1] */
    printf("After p++: %d\n", *p);

    return 0;
}
p points to: 1
q points to: 5
q - p = 4
After p++: 2

Valid operations on pointers: add/subtract an integer, subtract two pointers to the same array, compare with == or !=. Multiplying or dividing pointers is illegal.

Pointers and Strings

A C string is a char array. A char * can point to it and step through it character by character:

#include <stdio.h>

int my_strlen(const char *s)
{
    const char *p = s;
    while (*p != '\0')
        p++;
    return (int)(p - s);
}

int main(void)
{
    char str[] = "Hello";
    printf("Length: %d\n", my_strlen(str));
    return 0;
}
Length: 5

Note const char *s — the const promises not to modify the string through this pointer. Always use const when a function only reads the string.

Pointers to Pointers

A pointer can point to another pointer. This is used in functions that need to change where a pointer points (e.g., memory allocation helpers), and in 2D arrays and argv:

#include <stdio.h>

int main(void)
{
    int   x   = 42;
    int  *p   = &x;
    int **pp  = &p;   /* pointer to pointer */

    printf("x   = %d\n",   x);
    printf("*p  = %d\n",  *p);
    printf("**pp= %d\n", **pp);

    **pp = 100;         /* modifies x through two levels of indirection */
    printf("x is now: %d\n", x);

    return 0;
}
x   = 42
*p  = 42
**pp= 42
x is now: 100

Pointers and Dynamic Memory

malloc returns a pointer to heap-allocated memory. Always check for NULL and always free:

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

int main(void)
{
    int n = 5;
    int *arr;
    int i;

    arr = (int *)malloc(n * sizeof(int));
    if (arr == NULL) {
        fprintf(stderr, "malloc failed\n");
        return 1;
    }

    for (i = 0; i < n; i++)
        arr[i] = i * i;

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

    free(arr);   /* always free what you malloc */
    return 0;
}
0 1 4 9 16

Common Pointer Mistakes

Mistake What goes wrong Fix
Using an uninitialised pointer Undefined behaviour — likely crash Always initialise: int *p = NULL;
Dereferencing NULL Segmentation fault Check if (p != NULL) before *p
Going out of array bounds Undefined behaviour, memory corruption Track the length; stop before arr + n
Using a pointer after free() Use-after-free — undefined behaviour Set to NULL immediately after free(ptr); ptr = NULL;
Returning a pointer to a local variable Dangling pointer — stack frame gone Return heap-allocated memory or pass output buffer as parameter

How to Compile

gcc -ansi -Wall -Wextra -o pointers pointers.c

What Pointers Unlock

  • Pass large structs to functions without copying them — pass a pointer instead
  • Build dynamic data structures: linked lists, trees, graphs
  • Write functions that return multiple values by modifying via pointer parameters
  • Use function pointers for callbacks, dispatch tables, and state machines
  • Work with dynamic memory allocation (malloc/free)

Related C Programs

📖 Chapter 5 of The C Programming Language by K&R (Amazon.in) · Amazon.com is the definitive treatment of pointers and arrays — 20 exercises, all solved on this site.

Want to test your pointer knowledge? Try the C Programming Quiz — the Pointers category has 18 questions on dereferencing, arithmetic, and common mistakes. Free on Android.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>