Pointers and addresses

Every byte of memory has a number: its address. A variable lives at some address, and a pointer is simply a variable whose value is an address.

Two operators do all the work:

  • &x means "the address of x".
  • *p means "the thing at the address stored in p". This is called dereferencing.
int score = 10;
int *p = &score;   // p holds the address of score
*p = 99;           // write 99 into whatever p points at
// score is now 99

int *p reads as "p is a pointer to an int". The type matters: it tells the compiler what kind of value lives at that address and how many bytes to read when you write *p.

A pointer is itself just a number stored in memory, so it has a size too: 4 bytes on this 32-bit runner, 8 on a typical 64-bit laptop. You can print one with %p (it expects a void *, so write printf("%p\n", (void *)p);), but the actual address changes between machines and runs, which is why no exercise here asks you to print one.

A pointer that points nowhere is written NULL. Dereferencing NULL is undefined behaviour. On a laptop it usually crashes with a segmentation fault; in this WebAssembly runner, address 0 is valid memory, so it may quietly read junk instead. Either way, it is a bug. Same for an uninitialised pointer: it holds a random address, and writing through it scribbles on random memory.

Remember the & in scanf("%d", &n)? Now you know why: scanf needs to know where n lives so it can write into it.

Try it yourself

Edit it. Break it. Run it again.
#include <stdio.h>

int main(void) {
    int score = 10;
    int *p = &score;

    printf("score = %d, *p = %d\n", score, *p);
    *p = 99;
    printf("after *p = 99, score = %d\n", score);
    score = 5;
    printf("after score = 5, *p = %d\n", *p);
    printf("this pointer takes %zu bytes here\n", sizeof(p));
    return 0;
}
Ctrl/Cmd + Enter runs. Esc, then Tab, leaves the editor.

Your turn

Type it yourself. That is the whole trick.

1Write through a pointer

p already points at lives. Without writing lives = anywhere, use p to set lives to 3, then add 1 to it through p again. Print: lives: 4

#include <stdio.h>

int main(void) {
    int lives = 0;
    int *p = &lives;

    printf("lives: %d\n", lives);
    return 0;
}
Ctrl/Cmd + Enter runs. Esc, then Tab, leaves the editor.

2Aim the pointer

Make p point at whichever of a and b is larger, then set that variable to 0 through p. Print: a = 12, b = 0

#include <stdio.h>

int main(void) {
    int a = 12;
    int b = 30;
    int *p = NULL;

    // point p at the larger one, then set it to 0 through p

    printf("a = %d, b = %d\n", a, b);
    return 0;
}
Ctrl/Cmd + Enter runs. Esc, then Tab, leaves the editor.

Code editor. Press Control or Command plus Enter to run the code. Tab indents; to move focus out of the editor, press Escape and then Tab.