Pointers
The idea C is famous for: a variable that holds the address of another. Less scary than its reputation.
- 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.
Try it
Up to 15 XPFollow the address
Solve two memory missions by choosing what p points to, then writing through *p. Watch the values in the address cards and avoid dereferencing NULL.
Mission 1: Make x = 8 while y stays 12
Score 0/2Illustrative addresses only; real addresses vary between runs. This model never dereferences an invalid pointer.
Choose an address for p before writing through it.
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:
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
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}30 31
Two different jobs for * - this is where most confusion comes from:
- In a declaration,
int *pmeans "p is a pointer to an int". - In an expression,
*pmeans "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:
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}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).
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}10 20 30
Key takeaways
A pointer holds an address.
&xis the address ofx;*pis 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 dereferenceNULL, 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 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.
Two results at once
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
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.
Loading posts…