Scope and lifetime
Understand where variables are visible in C (scope) and how long they exist in memory (lifetime) — including local, global, and static local variables.
- Define scope as the region of code where a name is visible
- Explain that local variables are created when a function is called and destroyed when it returns
- Use a global variable and explain when that is appropriate
- Explain what a static local variable does
Every variable in C has two independent properties: scope (where in the source code it is visible) and lifetime (how long it exists in memory). Understanding both prevents a class of bugs that arise when variables outlive their usefulness or are used outside their visible region.
Scope
Scope is determined by where a declaration appears in the source code.
Local scope (block scope): Variables declared inside {...} braces are visible only within those braces and their nested braces.
#include <stdio.h>
int main(void) {
int x = 10; /* visible in main */
{
int y = 20; /* visible only in this inner block */
printf("x=%d y=%d\n", x, y);
}
/* printf("y=%d\n", y); */ /* ERROR: y is out of scope here */
return 0;
}Function parameters are local to the function body:
int add(int a, int b) {
return a + b; /* a and b visible here */
}
/* a and b do not exist outside add */Global scope (file scope): Variables declared outside any function are visible throughout the entire file, from the point of declaration to the end of the file.
#include <stdio.h>
int global_count = 0; /* visible to all functions below this line */
void increment(void) {
global_count++;
}
int main(void) {
increment();
increment();
printf("count: %d\n", global_count); /* 2 */
return 0;
}Use global variables sparingly. They make code hard to reason about because any function can modify them. Reserve globals for constants (const int MAX_SIZE = 100;) and for state that genuinely must be shared across many functions without being passed around. When in doubt, pass values as parameters instead.
Lifetime
Lifetime is about memory: when is the storage for a variable allocated and when is it released?
Local variables (automatic storage): allocated when the function is called, released when the function returns. This is the stack. Each call gets its own copy.
void count_up(void) {
int count = 0; /* re-initialised to 0 on every call */
count++;
printf("count = %d\n", count); /* always prints 1 */
}Global variables (static storage): allocated when the program starts, released when the program exits. They are initialised once, to zero by default.
Static local variables
static applied to a local variable gives it static lifetime while keeping local scope — the value persists between calls:
#include <stdio.h>
void count_calls(void) {
static int count = 0; /* initialised once; persists between calls */
count++;
printf("Called %d time(s)\n", count);
}
int main(void) {
count_calls(); /* Called 1 time(s) */
count_calls(); /* Called 2 time(s) */
count_calls(); /* Called 3 time(s) */
return 0;
}The static keyword makes count behave like a global (persists) but look like a local (only visible inside count_calls). This is useful for counters, caches, and state that should be owned by a single function.
Name shadowing
When a local variable has the same name as an outer variable, it shadows the outer one — the inner declaration is used within its scope:
#include <stdio.h>
int x = 100; /* global */
int main(void) {
int x = 5; /* local -- shadows the global */
printf("x = %d\n", x); /* 5, not 100 */
return 0;
}This compiles without error but is confusing. Avoid naming local variables the same as globals. gcc with -Wshadow warns about this.
Variable initialisation and lifetime
Local variables that are not explicitly initialised contain indeterminate values — whatever bytes happened to be in that stack memory. Global and static variables are zero-initialised by the C standard.
int global; /* 0 by C standard */
void f(void) {
int local; /* indeterminate -- do not read before writing */
static int s; /* 0 by C standard */
}Always initialise local variables before reading them.
A practical example: running average
#include <stdio.h>
void update_average(double value) {
static int count = 0;
static double sum = 0.0;
count++;
sum += value;
printf("Average after %d values: %.2f\n", count, sum / count);
}
int main(void) {
update_average(10.0);
update_average(20.0);
update_average(15.0);
return 0;
}The static variables accumulate state across calls without exposing that state globally. This is a pattern you will see in embedded and systems code.
Where to go next
Next: recursion — functions that call themselves, and how to think about the base case and recursive case to avoid infinite recursion.
Parameters and return values
Understand how C passes arguments by value, how to use pointers to modify caller variables, and patterns for returning multiple results.
Recursion basics
Write recursive functions in C — understanding the call stack, base cases, and recursive cases through factorial and Fibonacci examples.