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:
&x— address-of: returns the address wherexlives in memory*ptr— dereference: 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
- Array Summation Using Pointers
- Function Pointers in C – Callbacks and Dispatch Tables
- String Functions in C – Complete Reference
- K&R Chapter 5 — Pointers and Arrays (all exercises solved)
- All 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.