Loading
0x90Lesson 10 of 15

Pointers

The idea C is famous for: a variable that holds the address of another. Less scary than its reputation.

16 min 6-question quiz 1 code exercise
By the end of this lesson you can
  • Explain what an address and a pointer are
  • Use & to take an address and * to follow a pointer
  • Write a function that changes its caller's variables

Memory is one long row of bytes, and every byte has a number: its address. Every variable lives at some address. A pointer is simply a variable whose value is an address - it "points at" another variable. That is the whole idea; the rest is syntax.

Addresses with &

The & operator gives you the address of a variable. (You have already used it with scanf: &number told scanf where to write.) Addresses print with %p, and they will be different every time you run the program:

address.c
1#include <stdio.h>
2
3int main(void) {
4    int age = 30;
5    printf("age holds %d\n", age);
6    printf("age lives at %p\n", (void *)&age);
7    return 0;
8}

Declaring and following a pointer

pointer.c
1#include <stdio.h>
2
3int main(void) {
4    int age = 30;
5    int *p = &age;     // p holds the address of age
6
7    printf("%d\n", *p);  // follow p: prints 30
8
9    *p = 31;           // write through p
10    printf("%d\n", age); // age changed: prints 31
11    return 0;
12}
Output
30
31

Two different jobs for * - this is where most confusion comes from:

  • In a declaration, int *p means "p is a pointer to an int".
  • In an expression, *p means "the thing p points at" - this is called dereferencing.

So *p = 31; does not change p at all. It goes to the address stored in p and writes 31 there - into age.

Why pointers: changing the caller's variables

Remember that functions get copies of their arguments. To let a function change the caller's variable, pass its address instead - the function gets a copy of the address, and a copy of an address still leads to the same place:

swap.c
1#include <stdio.h>
2
3void swap(int *a, int *b) {
4    int temp = *a;
5    *a = *b;
6    *b = temp;
7}
8
9int main(void) {
10    int x = 1, y = 2;
11    swap(&x, &y);
12    printf("x = %d, y = %d\n", x, y);
13    return 0;
14}
Output
x = 2, y = 1

This is exactly how scanf works, and it is also how C functions "return" more than one value: the caller passes addresses for the results to be written into.

NULL

NULL is a special pointer value meaning "points at nothing". It is useful as a "no result" marker, and it is what you should set a pointer to when it has nothing valid to point at yet. Dereferencing NULL is undefined behavior - usually an immediate crash ("segmentation fault"). Check before you follow a pointer that might be NULL.

Pointers and arrays

An array name used in an expression turns into ("decays to") a pointer to its first element - which is why passing an array to a function passes an address. You can do pointer arithmetic: p + 1 points at the next element, not the next byte, because the compiler knows the element size. In fact, a[i] is defined as *(a + i).

walk.c
1#include <stdio.h>
2
3int main(void) {
4    int values[] = {10, 20, 30};
5    int *p = values;   // same as &values[0]
6
7    printf("%d\n", *p);
8    printf("%d\n", *(p + 1));
9    printf("%d\n", p[2]);
10    return 0;
11}
Output
10
20
30

Key takeaways

  • A pointer holds an address. &x is the address of x; *p is the value p points at.

  • Pass addresses (swap(&x, &y)) when a function must change its caller's variables.

  • Initialize pointers (to a real address or NULL), never dereference NULL, and never keep the address of a local variable after its function returns.

Lesson quiz

6 questions · pass with 5 correct · up to 50 XP

Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.

Practice: write real C

These run for real. Write the program, press Run tests, and read what the compiler tells you - learning to read compiler messages is half of learning C.

Exercise 1

Two results at once

+25 XP

Write void min_max(const int values[], int length, int *min, int *max) that stores the smallest and largest element through the two pointers. main reads a count and that many numbers, calls your function, and prints the results.

For 5 then 3 9 -2 7 4, the output is min=-2 max=9.

  • Mixed values
  • One value
main.c
Loading editor…

Your code is compiled with gcc 14 (-Wall -Wextra) and run on Compiler Explorer (godbolt.org), a free public service.

Questions about this lesson

Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.

Sign in to ask questions, help other learners, and earn XP for taking part.

Loading posts…

Did you like the lesson? 😆👍
Consider a donation to support our work: