Code of the Day
BeginnerFunctions

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.

CBeginner10 min read
By the end of this lesson you will be able to:
  • 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.

Finished reading? Mark it complete to track your progress.

On this page