Nearby lessons

87 of 124

C - Pointer Introduction

A pointer is a variable that stores a memory address. Learn what pointers are, the two operators & and * that make them work, and why C would be a far weaker language without them.

A Variable That Holds an Address

An ordinary variable holds data. A pointer holds the location of data:

DeclarationStoresExample content
int x = 42;The number 4242
int *p = &x;Where x lives0x7ffd1000
Example01
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int x = 42;
6 int *p = &x; /* p holds the ADDRESS of x */
7 
8 printf("x = %d\n", x);
9 printf("&x = %p\n", (void *) &x);
10 printf("p = %p (the same address)\n", (void *) p);
11 printf("*p = %d (the value it points to)\n", *p);
12 return 0;
13}
Output
x  = 42
&x = 0x7ffd4a2b1c4c
p  = 0x7ffd4a2b1c4c   (the same address)
*p = 42   (the value it points to)

The Two Operators

In simple words: & asks "where does this live?" and gives you an address. * asks "what is at this address?" and gives you the value. They are exact opposites, and *&x is just x.
Example02
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int x = 10;
6 int *p = &x;
7 
8 printf("x = %d\n", x);
9 printf("*&x = %d (& then * cancels out)\n", *&x);
10 printf("*p = %d\n", *p);
11 printf("&*p = %p (also just &x)\n", (void *) &*p);
12 return 0;
13}
Output
x     = 10
*&x   = 10   (& then * cancels out)
*p    = 10
&*p   = 0x7ffd8c1a2344 (also just &x)

Writing Through a Pointer

*p is not read-only. Assign to it and you change the original variable — this is what makes pointers powerful:

Example03
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int x = 10;
6 int *p = &x;
7 
8 printf("Before : x = %d\n", x);
9 
10 *p = 99; /* writes into x */
11 
12 printf("After : x = %d\n", x);
13 printf("Both agree: x=%d, *p=%d\n", x, *p);
14 return 0;
15}
Output
Before : x = 10
After  : x = 99
Both agree: x=99, *p=99

The Pointer Type Matters

int *, char * and double * all store an address of the same size. The type tells C how many bytes to read and how to interpret them:

Example04
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int i = 65;
6 char c = 'A';
7 double d = 3.14;
8 
9 int *pi = &i;
10 char *pc = &c;
11 double *pd = &d;
12 
13 printf("All pointers are the same size:\n");
14 printf(" int * : %zu bytes\n", sizeof(pi));
15 printf(" char * : %zu bytes\n", sizeof(pc));
16 printf(" double * : %zu bytes\n", sizeof(pd));
17 
18 printf("But they read different amounts:\n");
19 printf(" *pi = %d (%zu bytes)\n", *pi, sizeof(*pi));
20 printf(" *pc = %c (%zu byte)\n", *pc, sizeof(*pc));
21 printf(" *pd = %.2f (%zu bytes)\n", *pd, sizeof(*pd));
22 return 0;
23}
Output
All pointers are the same size:
  int *    : 8 bytes
  char *   : 8 bytes
  double * : 8 bytes
But they read different amounts:
  *pi = 65  (4 bytes)
  *pc = A  (1 byte)
  *pd = 3.14 (8 bytes)

Why C Needs Pointers

Five things you simply cannot do in C without them:

NeedWhy a pointer is required
Modify a caller's variableArguments are copies; an address is not
Return several valuesreturn sends back only one
Dynamic memorymalloc hands back an address
Efficient large dataPass 8 bytes instead of copying a big struct
Linked lists and treesNodes must reference other nodes
Example05
CCode Cell
1#include <stdio.h>
2 
3/* Without a pointer: the caller sees nothing change */
4void brokenSwap(int a, int b) { int t = a; a = b; b = t; }
5 
6/* With pointers: it works */
7void workingSwap(int *a, int *b) { int t = *a; *a = *b; *b = t; }
8 
9int main()
10{
11 int x = 1, y = 2;
12 
13 brokenSwap(x, y);
14 printf("brokenSwap : x=%d y=%d\n", x, y);
15 
16 workingSwap(&x, &y);
17 printf("workingSwap: x=%d y=%d\n", x, y);
18 return 0;
19}
Output
brokenSwap : x=1 y=2
workingSwap: x=2 y=1

You Have Been Using Pointers All Along

scanf, array names and string functions are all pointer-based. Pointers were there from your first program:

Example06
CCode Cell
1#include <stdio.h>
2#include <string.h>
3 
4int main()
5{
6 int n;
7 char s[20] = "Hello";
8 
9 scanf("%d", &n); /* passing an address */
10 
11 printf("s = %p\n", (void *) s); /* array name IS a pointer */
12 printf("&s[0] = %p (identical)\n", (void *) &s[0]);
13 
14 strcpy(s, "World"); /* strcpy takes two pointers */
15 printf("s = %s\n", s);
16 return 0;
17}
Output
5
s     = 0x7ffd1c2a3b40
&s[0] = 0x7ffd1c2a3b40 (identical)
s = World

Two Pointers to One Variable

Nothing stops several pointers from referring to the same location. All of them see every change:

Example07
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int shared = 100;
6 int *p1 = &shared;
7 int *p2 = &shared;
8 
9 printf("Start : shared=%d *p1=%d *p2=%d\n", shared, *p1, *p2);
10 
11 *p1 = 200; /* changed through p1 */
12 printf("Via p1: shared=%d *p1=%d *p2=%d\n", shared, *p1, *p2);
13 
14 *p2 = 300; /* changed through p2 */
15 printf("Via p2: shared=%d *p1=%d *p2=%d\n", shared, *p1, *p2);
16 return 0;
17}
Output
Start : shared=100 *p1=100 *p2=100
Via p1: shared=200 *p1=200 *p2=200
Via p2: shared=300 *p1=300 *p2=300

Common Mistakes

  • Dereferencing an uninitialised pointerint *p; *p = 5; writes to a random address.
  • Assigning a value instead of an addressint *p = 42; makes 42 the address.
  • Confusing p with *p — one is the address, the other is the value.
  • Mismatched pointer typesint *p = &someChar; reads 4 bytes where only 1 belongs.
  • Keeping a pointer to a dead local — a dangling pointer.
Always give a pointer something valid to point to before you dereference it. int *p; *p = 5; compiles without complaint and then writes 5 to whatever garbage address happened to be in p. Initialise at declaration — either to a real address or to NULL, then check before use.
📝 Key Takeaways
  • A pointer holds an address, not a value.
  • & takes an address; * follows one (dereference).
  • Every pointer has a type that tells C how to read the target.
  • All pointers are the same size regardless of what they point to.
  • Pointers enable output parameters, dynamic memory and data structures.

🧠 Test Your Knowledge

4 Questions
Progress: 0 / 4