Pointers Basics & Memory Addresses
Every variable in your program lives somewhere in the computer's memory, and that location has a numeric address, just like every house on a street has an address. Normally you never see these addresses — you just refer to variables by name, and C handles the lookup for you behind the scenes.
int age = 25;
int *ptr = &age; // ptr now stores the ADDRESS of age
printf("%d\n", age); // 25 - the value
printf("%p\n", &age); // e.g. 0x7ffee3a3 - the address
printf("%p\n", ptr); // same address - ptr points to age
printf("%d\n", *ptr); // 25 - dereferencing: 'follow the pointer to its value'
The asterisk * means two different things depending on context: in a declaration (int *ptr) it marks the variable as a pointer; in an expression (*ptr) it dereferences the pointer, meaning "give me the value stored at this address."
int age = 25;
int *ptr = &age;
*ptr = 30; // changes age itself, through the pointer!
printf("%d\n", age); // 30
This is the real power of pointers: dereferencing with *ptr = 30; reaches through the pointer and modifies the original variable directly, not just a copy.
A pointer that isn't pointing at any valid variable should be set to NULL rather than left uninitialized, and should always be checked before being dereferenced:
int *ptr = NULL;
if (ptr != NULL) {
printf("%d\n", *ptr);
} else {
printf("Pointer is not pointing to anything yet\n");
}
Declaring int *ptr; without immediately setting it to point somewhere valid (or to NULL) leaves it pointing at a random, garbage memory address. Dereferencing it with *ptr before assigning it a real address is undefined behavior and a very common cause of program crashes.
Create an int variable, a pointer to it, print the value both directly and through the pointer, then change the value using the pointer and confirm the original variable changed too.
#include <stdio.h>
int main() {
int score = 75;
int *ptr = &score;
printf("Before: %d\n", score);
*ptr = 95;
printf("After: %d\n", score);
return 0;
}