Three independent questions about every identifier: where can the name be used (scope), how long does the object exist (storage duration) and can other files see it (linkage).
Scope — where a name is visible
| Scope | Begins / ends | Example |
|---|---|---|
| Block | Declaration → closing } | Locals, loop variables for (int i…) |
| File | Declaration → end of translation unit | Globals, functions |
| Function | Whole function | Only goto labels |
| Function prototype | End of the prototype | int f(int n); — the name n |
#include <stdio.h>
int x = 1; /* file scope */
int main(void) {
printf("global x = %d\n", x);
int x = 2; /* shadows the global */
{
int x = 3; /* shadows the outer local */
printf("inner x = %d\n", x);
}
printf("local x = %d\n", x);
for (int i = 0; i < 1; i++) {
printf("i = %d\n", i);
}
/* i is out of scope here */
return 0;
}global x = 1
inner x = 3
local x = 2
i = 0Storage duration — how long the object lives
| Duration | Objects | Lifetime | Where |
|---|---|---|---|
| Automatic | Locals, parameters | Until the block exits | Stack |
| Static | Globals, static locals, string literals | Whole program | .data / .bss / .rodata |
| Allocated | malloc / calloc / realloc | Until free | Heap |
| Thread (C11) | _Thread_local | Lifetime of the thread | Per-thread storage |
Lifetime ends while a pointer lives on
#include <stdio.h>
int *make_counter(void) {
int count = 0;
return &count; /* address of a local that dies on return */
}
int main(void) {
int *p = make_counter();
printf("%d\n", *p);
return 0;
}main.c:5:13: error: address of stack memory associated with local variable 'count' returned [-Werror,-Wreturn-stack-address]Fixes: return the value itself, use a static local, let the caller pass a buffer, or allocate with malloc (caller frees).
Linkage — can other files see it?
What is the difference between scope and lifetime?
What is variable shadowing?