C global variables, scope, variable lifetime, and the static keyword explained.
Scope β Where a Variable Is Visible
The region where a variable can be referenced (its scope) is determined by where it is declared.
intmain(void) {
int a = 10; // valid inside mainif (a > 0) {
int b = 20; // valid only inside this blockprintf("%d\n", a+b); // OK
}
// printf("%d\n", b); β error! b is out of scope
}
Local variable
Valid only inside the function or block. Destroyed on exit.
Global variable
Declared outside any function. Accessible everywhere.
static variable
A local variable that retains its value between calls.
Variable Lifetime β When It Is Born and When It Dies
Scope tells you "from where it is visible." Lifetime tells you when the variable is allocated and freed in memory.
Three kinds of lifetime
Kind
Where declared
Created when
Destroyed when
auto (local)
inside a function/block
when the block is entered
when the block is exited
global
outside any function
program start
program end
static
inside a function (with static)
program start
program end
voidexample(void) {
int a = 1; // auto: created per call, gone on exitstaticint b = 1; // static: created once, value persists
a++; b++;
printf("a=%d b=%d\n", a, b);
}
intmain(void) {
example(); // a=2 b=2example(); // a=2 b=3 β a resets, b persistsexample(); // a=2 b=4
}
Visualize the lifetime
Click the button to animate how each variable changes as example() is called three times.
Step 0 / 9
Call state
Variables in memory
Output
Global Variables β Shared Across All Functions
#include<stdio.h>int counter = 0; // global variable (outside main, etc.)voidincrement(void) {
counter++; // usable without any argument
}
intmain(void) {
increment();
increment();
increment();
printf("%d\n", counter); // β 3
}
Don't overuse: Globals are convenient, but it is hard to trace where they are modified, so they invite bugs. Keep them to a minimum.
static Variables β Persist Across Calls
A regular local variable is destroyed when the function returns, but adding static makes it live until the program ends.
voidcount(void) {
staticint n = 0; // initialized to 0 only once
n++;
printf("Call count: %d\n", n);
}
intmain(void) {
count(); // β 1count(); // β 2count(); // β 3
}
When to use: When you need to know "how many times a function was called" or remember a previous result β especially when you want state without the risks of globals.
Memory Layout β Where Do Variables Actually Live?
Local, global, and static variables are stored in different memory regions. This is the real reason their "lifetimes" differ.
Memory map of a C program
When a C program runs, memory is divided into 5 regions:
High address β
π Stack
Local variables, function arguments, return addresses. Automatically allocated/freed on each function call.
β grows down β
(free space)
β grows up β
π§± Heap
Dynamically allocated via malloc/free. Managed explicitly by the programmer.
π BSS (Uninitialized Data)
Uninitialized global and static variables. Auto-zeroed at program start.
πΎ Data (Initialized)
Initialized global and static variables. Lives for the entire program.
π Text (Code)
Machine code and string literals. Read-only.
Low address β
Code mapped to regions
#include<stdio.h>#include<stdlib.h>int g_init = 100; // πΎ Data segment (initialized)int g_uninit; // π BSS (uninitialized β auto-zeroed)voidfunc(void) {
int local = 5; // π Stack (new copy per call)staticint s = 0; // πΎ Data segment (created once)int *heap = malloc(sizeof(int)); // π§± Heap
*heap = 42;
free(heap);
}
intmain(void) {
func();
return0;
}
Variable types and their memory regions
Variable type
Declared in
Memory region
Created
Initial value
Local (auto)
Inside function
π Stack
On function call
Undefined (garbage)
Local (static)
Inside function + static
πΎ Data / BSS
At program start
0 or specified value
Global (initialized)
Outside any function
πΎ Data
At program start
Specified value
Global (uninitialized)
Outside any function
π BSS
At program start
0 (automatic)
malloc'd
Dynamic inside function
π§± Heap
On malloc call
Undefined (calloc: 0)
String literal
Source code "..."
π Text
At program start
Read-only
Function calls and the stack
Each function call pushes a stack frame. Returning automatically pops it.
voidb(void) { int y = 20; } // b's framevoida(void) { int x = 10; b(); } // a's frameintmain(void) { a(); return0; }
Stack when main β a() β b() is in progress:
b() frame (y=20) β top (pushed last)
a() frame (x=10)
main() frame
When b() returns, its frame is popped; then a() returns and its frame is popped too.
What is a stack overflow? Too much recursion or too many nested calls exhausts the stack region, causing a Segmentation Fault.
"Lifetime" explained via memory regions
Short-lived = Stack
Local variables. Disappear when function ends. Fast, but can't persist across calls.
Long-lived = Data/BSS
Global/static. Live for the whole program. Always accessible, but overuse hurts maintainability.
Flexible = Heap
Allocated with malloc, freed with free. You control size and lifetime. Forgetting free = memory leak.