Scope and Storage Classes
Where a variable can be seen, and how long it lives.
7 minute read
Big idea
Scope is where a name can be used. Storage is how long the variable lives. Most variables live inside { } and vanish at the } — static and globals live for the whole program.
Local variables
A variable declared inside a function (or any { } block) is local: only code inside that block can see it, and it's created fresh each time the block runs.
void f(void) {
int count = 0; // local to f
}
// count doesn't exist out here
Two functions can each have their own count — they're different variables that happen to share a name.
Global variables
A variable declared outside every function is global: every function below it can see it, and it lives as long as the program runs. If you don't initialise it, it starts at 0.
#include <stdio.h>
int total = 0; // global
void add(int x) {
total += x;
}
int main(void) {
add(5);
add(7);
printf("total = %d\n", total);
return 0;
}output
total = 12Run and edit it in the app.
Handy, but every function can change a global, so when it has the wrong value, any line in the program could be the culprit. Prefer parameters and return values; reach for globals rarely.
Shadowing
A local with the same name as a global hides the global inside its block:
#include <stdio.h>
int x = 1;
int main(void) {
printf("%d\n", x);
int x = 2;
printf("%d\n", x);
{
int x = 3;
printf("%d\n", x);
}
printf("%d\n", x);
return 0;
}What does it print? Show the answer
1
2
3
2Run and edit it in the app.
Each { } can declare its own x; the innermost one wins until its block ends. Legal — but confusing. Give things different names.
Watch the names get hidden
static: a local that remembers
Put static on a local variable and it's created once, keeps its value between calls, and is still only visible inside its function:
Take static away and every call prints 1 — try it:
#include <stdio.h>
int next_ticket(void) {
int number = 0;
number++;
return number;
}
int main(void) {
for (int i = 0; i < 3; i++) {
printf("Ticket %d\n", next_ticket());
}
return 0;
}output
Ticket 1
Ticket 2
Ticket 3Run and edit it in the app.
The storage-class keywords
| Keyword | On a local | On a global or function |
|---|---|---|
| (none) | automatic: made each time the block runs, gone at its } | visible to other files of the program |
static | lives for the whole program, keeps its value | private to this file |
extern | — | "this exists, defined in another file" — a declaration, not a new variable |
register | a hint to keep it in a CPU register; you can't take its & | — |
externmatters once a program is split over several files — see Multi-File Programs.registeris a leftover from old compilers; modern ones decide better than we can. You'll read it in old code, but there's no need to write it.
void f(void) { static int n = 10; n += 5; printf("%d ", n); } — what do three calls to f() print?
Common mistake
Returning the address of an ordinary local:
int *bad(void) {
int x = 42;
return &x; // ✗ x dies when bad() returns
}
The caller gets a dangling pointer to memory that's already been reused. Return the value, use static, or use malloc.
Think of it like
A local variable is a whiteboard in a meeting room — wiped when the meeting ends. A static local is a notebook kept in that room's drawer: only people in the room use it, but it's still there next meeting. A global is the noticeboard in the corridor — everyone can read it, and anyone can scribble on it.
Key terms
- Scope — The part of the code where a name is visible.
- Lifetime — How long a variable exists while the program runs.
- Local (automatic) variable — Declared in a block; lives until the block ends.
- Global variable — Declared outside functions; lives for the whole program.
static— On a local: keeps its value between calls. On a global or function: private to its file.- Shadowing — An inner variable hiding an outer one with the same name.
Check yourself
When does an ordinary local variable stop existing?
What does static do to a local variable?
What does extern int count; mean?