Addresses and pointers
So far we have used variables only by their names. But every variable lives somewhere in memory, and that place has a number: its address. A pointer is a variable that holds an address. Pointers are the hardest step in C, so in this lesson, press Step often and watch where each arrow points.
Where a variable lives
Put & in front of a variable to get its address. To print an address, use the format specifier %p (and write (void *) in front, which is what %p expects).
1int score = 90;2printf("score = %d\n", score);3printf("&score = %p\n", (void *)&score);
On one computer, one run printed this:
score = 90 &score = 0x7ffd5e8a1c4c
An address is a number written in hexadecimal. It changes from computer to computer and from run to run: run these lines yourself and you will get a different one. There is nothing to remember about the number itself. Remember only this: every variable has an address, and & gets it.
Two variables can hold the same value, but each one has its own address. == works on addresses too:
1#include <stdio.h>2 3int main(void) {4 int a = 5;5 int b = 5;6 printf("a == b: %d\n", a == b);7 printf("&a == &b: %d\n", &a == &b);8 return 0;9}
a == b: 1 &a == &b: 0
1 means true and 0 means false (lesson 5). a and b are equal, but they live in two different places.
Now you can read scanf("%d", &age) from lesson 3: &age is the address of age. scanf needs to know where age is in memory so it can put the number there.
Pointers: variables that hold addresses
Read int *p as "p is a pointer to an int". Store &score in it and p points to score. A * in front of a pointer means "follow the address to the variable", so *p = 100 changes score.
1#include <stdio.h>2 3int main(void) {4 int score = 90;5 int *p = &score;6 *p = 100;7 printf("%d\n", score);8 return 0;9}
100
Press Step: p is drawn as an arrow pointing at score. After line 6, the score at the end of the arrow is 100, though line 6 never mentions score.
A pointer's type says what it points to. An int * points to an int, a double * to a double, a char * to a char:
1#include <stdio.h>2 3int main(void) {4 double price = 4.50;5 char grade = 'B';6 double *pp = &price;7 char *pg = &grade;8 *pp = *pp * 2;9 *pg = 'A';10 printf("%.2f %c\n", price, grade);11 return 0;12}
9.00 A
Two different stars
* shows up in two places, with two meanings:
| You write | Where | It means |
|---|---|---|
int *p | in a declaration | p is a pointer to an int |
*p | when you use it | the variable p points to |
&x | when you use it | the address of x |
So int *q = &n; declares q and stores the address of n in it. It does not put anything into *q. After that, *q reads n:
1#include <stdio.h>2 3int main(void) {4 int n = 7;5 int *q = &n;6 printf("n = %d, *q = %d\n", n, *q);7 n = 8;8 printf("n = %d, *q = %d\n", n, *q);9 return 0;10}
n = 7, *q = 7 n = 8, *q = 8
q doesn't hold a copy of 7. It holds where n is, so when n changes, *q sees the new value.
What does this print?
1#include <stdio.h>2 3int main(void) {4 int a = 1;5 int *p = &a;6 *p = *p + 5;7 printf("%d\n", a);8 return 0;9}
p points to a, so *p is a. *p = *p + 5 reads a (1), adds 5 and puts 6 back into a. It's the same as writing a = a + 5.
Pointing somewhere else
A pointer is a variable, so you can give it a new address. Assign to p (no star) to change where it points; assign to *p to change what is there.
1#include <stdio.h>2 3int main(void) {4 int apples = 3;5 int pears = 5;6 int *p = &apples;7 *p = 4;8 p = &pears;9 *p = 6;10 printf("apples %d, pears %d\n", apples, pears);11 return 0;12}
apples 4, pears 6
Press Step and watch the arrow: first it points at apples, and on line 8 it swings over to pears. Each *p = ... changes whichever variable the arrow points at right then.
Pointers that point nowhere
A pointer that was declared but never given a value holds a garbage address. Following it means reading or writing some random place in memory:
1#include <stdio.h>2 3int main(void) {4 int *p;5 *p = 5;6 printf("%d\n", *p);7 return 0;8}
use of uninitialized valueWhat happened: Stopped at line 5. A variable was used before it was given a value. In real C it would hold garbage, different on every run.
On a real computer, a program like this sometimes crashes and sometimes seems fine, which makes it one of the hardest bugs to find. Our engine stops on the line where it happens and tells you. Press "see how it went wrong".
When you don't know yet what a pointer should point to, set it to NULL, a special value that means "points to nothing". Check p != NULL before you use it:
1#include <stdio.h>2 3int main(void) {4 int stock = 12;5 int *p = NULL;6 if (p != NULL) {7 printf("before: %d\n", *p);8 }9 p = &stock;10 if (p != NULL) {11 printf("after: %d\n", *p);12 }13 return 0;14}
after: 12
Tip: Every pointer should get a value when you declare it: either the address of something, or NULL. Lesson 18 goes through what else can go wrong with pointers.
Practice
Write the code, then press Check. A hint costs nothing; the answer is there when you need it.
Raise the price
✓Don't write price directly: add 10 to it through p. The program should print price = 60.
price = 60
1#include <stdio.h>2 3int main(void) {4 int price = 50;5 int *p = &price;6 // add 10 to price through p7 8 printf("price = %d\n", price);9 return 0;10}
Point somewhere else
✓p points to a. Make it point to b instead, then set b to 0 through p. The program should print a = 3, b = 0.
a = 3, b = 0
1#include <stdio.h>2 3int main(void) {4 int a = 3;5 int b = 8;6 int *p = &a;7 8 printf("a = %d, b = %d\n", a, b);9 return 0;10}
Fix it
✓This program uses a pointer that was never given a value, and the engine stops. Change one line so it prints Temperature: 25.
Temperature: 25
1#include <stdio.h>2 3int main(void) {4 int temp = 21;5 int *p;6 *p = 25;7 printf("Temperature: %d\n", temp);8 return 0;9}
What you learned
- Every variable has an address in memory;
&xgives the address ofx, and%pprints it (it differs from run to run). int *p = &x;stores the address ofxinp:ppoints tox.*pis the variableppoints to: you can read it and change it.- In
int *pthe star declares a pointer; in*pit follows the pointer. p = &y;changes whereppoints;*p = 5;changes what is there.- Never use a pointer that has no value. When you don't know yet, set it to
NULLand check before using it.