Scope & Lifetime
Two closely related but distinct ideas govern every variable in C: scope (where in the source code a name is visible) and lifetime, also called storage duration (how long the variable's memory actually exists while the program runs). It's entirely possible for a name to go out of scope while its memory is still alive, or for a name to be in scope pointing at memory that no longer exists — both are common sources of bugs, so it's worth understanding the two concepts separately.
Kinds of scope
Block scope — a variable declared inside
{ }(a function body, anif, aforloop, or any nested block) is only visible from its declaration to the closing brace of that block.File scope — a variable or function declared outside every function, at the top level of a source file, is visible from its declaration to the end of that file (and possibly other files too, via
extern).Function scope — this term applies specifically to labels used with
goto; a label is visible throughout its entire enclosing function, regardless of which block it's declared in.
int file_scope_var = 100; /* visible to every function below, in this file */
void demo(void) {
int block_scope_var = 1; /* visible only inside demo() */
if (block_scope_var == 1) {
int nested_var = 2; /* visible only inside this if-block */
goto done; /* labels have function scope, not block scope */
}
done:
return;
}Kinds of lifetime (storage duration)
Storage duration | When memory is created | When memory is destroyed |
|---|---|---|
Automatic | When execution enters the enclosing block | When execution leaves the enclosing block |
Static | Once, before | When the program terminates |
Allocated (dynamic) | When you call | When you call |
Plain local variables have automatic storage duration — this is the same auto storage class covered on the previous page. Globals and static locals have static storage duration. Memory you request with malloc has its own lifetime entirely under your control, covered later in the memory management section.
Scope vs lifetime — a worked example
Here's the key experiment that makes the distinction concrete: an ordinary local variable declared inside a loop is recreated every iteration (new scope entry means new automatic lifetime), while a static variable in the same spot is created exactly once and simply keeps its value:
#include <stdio.h>
int main(void) {
for (int i = 0; i < 3; i++) {
int fresh = 0; /* automatic duration -- reborn every iteration */
static int kept = 0; /* static duration -- created once, ever */
fresh++;
kept++;
printf("iteration %d: fresh = %d, kept = %d\n", i, fresh, kept);
}
return 0;
}iteration 0: fresh = 1, kept = 1 iteration 1: fresh = 1, kept = 2 iteration 2: fresh = 1, kept = 3
Both fresh and kept have exactly the same scope — they're only nameable inside the loop body — but wildly different lifetimes. fresh is allocated and destroyed three separate times; kept is allocated once before the loop even starts running and lives until the program exits, quietly remembering its value between iterations even though its name is inaccessible outside the loop body.