Scope, lifetime and storage classes
Three related but distinct ideas that GATE mixes together. Where a name is visible (scope), how long the object exists (lifetime) and who else can link to it (linkage), plus what auto, static, extern and register change.
Why it exists
Two questions sound similar but are different. Where in the source can I use this name? (scope) and how long does the thing it names exist while the program runs? (lifetime). A local variable is visible only inside its block and normally exists only while that block runs, so the two coincide and people forget they are separate. Storage classes such as static and extern pull them apart, and many GATE questions on this topic are about a variable whose scope and lifetime differ.
Prerequisites
Precise definitions
Scope is the part of the program text in which a name can be used. C has four kinds, two of which matter for GATE:
- Block scope. A name declared inside
{ ... }(including function parameters and the variable of aforheader) is visible from just after its declarator to the end of that block. - File scope. A name declared outside every function is visible from just after its declarator to the end of the translation unit (the source file after preprocessing).
- Function prototype scope (parameter names in a declaration) and function scope (labels) are rarely tested.
Shadowing. A name in an inner block hides the same name from an outer block (or from file scope) until the inner block ends. C uses static (lexical) scoping: which declaration a name refers to is decided by the program text, never by who called whom.
Lifetime (storage duration) is the part of the run during which the object exists.
- Automatic: created when execution enters the block, destroyed when it leaves. Default for locals. A fresh copy each time, holding garbage unless initialised.
- Static: exists for the whole run and is initialised once, to zero (or null pointers) unless you give a constant initialiser. Globals and
staticlocals. (C11 also has thread duration,_Thread_local, which GATE does not need.) - Allocated: from
malloctofree(see the memory layout page).
Linkage says whether the same name in different scopes or files refers to the same object or function: external (shared, the default for file-scope functions and variables), internal (private to the file, static at file scope), or none (block-scope locals without extern, parameters, and names such as typedefs and labels).
Storage-class specifiers:
| Specifier | At file scope | Inside a function |
|---|---|---|
| (none) | external linkage, static duration | auto: automatic duration, no linkage |
auto | not allowed | the default for locals; almost never written |
static | internal linkage (private to this file), static duration | static duration: one persistent copy, still local in scope |
extern | a declaration with external linkage (internal if an earlier static declaration is visible). It is only a declaration unless it has an initialiser, which makes it a definition | declares that the name refers to an object or function with linkage defined elsewhere; with an initialiser it is a constraint violation |
register | not allowed | hint to keep it in a CPU register; you may not take its address (&x is an error) |
Initialisation rules.
- Objects with static duration (globals and
staticlocals) are initialised once, before the program starts. The initialiser must be a constant expression (static int a = f();is an error in C). - Automatic objects are initialised each time the declaration is executed. Without an initialiser their value is indeterminate.
How it works
Step through three calls to the same function. Watch what disappears and what stays. The frame for counter holds the automatic a, which is created at 0 and vanishes on return. The globals and statics sit outside the stack in the data area and keep counting. Amber marks a value that has just changed.
Automatic, static and global variables
Real run, real addressesC source
Stack framesnewest on top
main()
no variables yet
Globals and statics (data area, not on the stack)
Step 1
Before any call: g exists (initialised to 0). The static s will join once counter runs.
The rule to remember: in the usual implementation, only automatic variables live in frames. static locals have the scope of a local but the lifetime of a global, which is exactly why they are tested.
Worked examples
EX 1Shadowing in nested blocks
Easy#include <stdio.h>
int x = 1;
int main(void) {
printf("%d ", x);
{
int x = 2;
printf("%d ", x);
{
int x = 3;
printf("%d ", x);
}
printf("%d ", x);
}
printf("%d\n", x);
return 0;
}Output:
1 2 3 2 1Reading it. Each inner x hides the outer one only while its block is running. When a block ends, the previous x is visible again, with the value it had before. The global x is never changed.
EX 2Static against automatic inside a loop
Medium#include <stdio.h>
int main(void) {
for (int i = 0; i < 3; i++) {
static int s = 0;
int a = 0;
s += 2;
a += 2;
printf("%d %d ", s, a);
}
printf("\n");
return 0;
}Output:
2 2 4 2 6 2Step 1. static int s = 0; is initialised once, not on every loop pass. So s goes 2, 4, 6.
Step 2. int a = 0; is executed on every pass, so a starts at 0 each time and ends each pass at 2.
EX 3A static local initialised once
Medium#include <stdio.h>
int f(void) {
static int n = 10;
n += 5;
return n;
}
int main(void) {
int first = f();
int second = f();
printf("%d %d\n", first, second);
return 0;
}Output:
15 20Why not 15 15. The initialisation = 10 is not an assignment that runs on every call. It happened once, before main. After that, each call just adds 5 to the surviving value.
EX 4Global against local with the same name
GATE level#include <stdio.h>
int i = 10;
void f(void) {
int i = 5;
i++;
printf("%d ", i);
}
int main(void) {
f();
f();
i++;
printf("%d\n", i);
return 0;
}Output:
6 6 11Step by step. In f the local i hides the global i. Each call creates a new local set to 5, increments it to 6 and prints it, so the first two numbers are both 6. In main there is no local i, so i++ changes the global from 10 to 11.
EX 5Static versus dynamic scoping (not C)
GATE levelC is statically scoped, but GATE (and compiler courses) also ask what a program would print under dynamic scoping, where a non-local name is looked up in the caller's variables at run time. Take this program in pseudocode:
x = 1
procedure f() { print x }
procedure g() { local x = 2; call f() }
call g()
call f()- Static scoping (C, Java, Python):
fwas written where only the globalxis visible, sofalways prints the globalx. Output:1then1. - Dynamic scoping:
fuses the most recent still-active binding ofxalong the call chain. Called fromg, the most recentxisg's local, so it prints2. Called from the top level it prints1. Output:2then1.
You can check this for real in bash, whose local variables are dynamically scoped: running the same structure there prints exactly f sees x = 2 and then f sees x = 1. In C the equivalent program prints 1 and 1, because f can only see the global.
Cheat box
Cheat box
- Scope = where the name is visible (text). Lifetime = how long the object exists (run time). Linkage = whether other files can refer to it.
- Locals: block scope, automatic lifetime, new copy per call, garbage if uninitialised.
- Globals and
staticlocals: static lifetime, initialised once, zero by default. staticinside a function: local scope, global lifetime.staticat file scope: file-private (internal linkage).externalone declares, it does not define (an initialiser makes it a definition).register: you cannot take the address.- Inner declarations shadow outer ones until their block ends.
- C is lexically scoped: the declaration is chosen by the text, not the call chain.
staticinitialiser: a constant expression, evaluated once.
Traps and GATE patterns
Connections
Across subjects
Within this subject
Where each kind of variable physically lives is on the memory layout page. A compiler implements these rules with a symbol table for scope and with activation records for automatic storage, and the way recursion keeps a fresh copy per call is explained in recursion and the call stack.
PYQs
8 previous year questions from your book. I re-solved each one myself (8 by running or simulating, 0 by reasoning only); the book's key is shown next to my answer. All PYQs
Consider the following C program:
#include <stdio.h>
int r ( )
{
static int num=7;
return num--;
}
int main ( )
{
for (r ( ); r ( ); r ( ))
printf ("%d", r ( ));
return 0;
}
Which one of the following values will be displayed
on execution of the programs?- (a)41
- (b)63
- (c)52
- (d)630
Consider the following three ANSI – C programs. P1,
P2, and P3
P1
P2
P3
#include
<stdio.h>
int a = 5;
int main(){
int a = 7;
return(0);
}
#include
<stdio.h>
int main(){
int a=5;
int a=7;
return(0);
}
#include
<stdio.h>
int main(){
int a=5;
float a=7;
return(0);
}
Which one of the following statement is true?- (a)Only P1 will compile without any error
- (b)Only P2 will compile without any error
- (c)Only P3 will compile without any error
- (d)All three programs P1, P2, and P3 will compile without any error
Consider the following program in C:
#include <stdio.h>
void func(int i, int j) {
if (i < j) {
int i = 0;
while (i < 10) {
j += 2;
i++
}
}
printf("%d", i);
}
int main() {
int i = 9, j = 10;
func(i, j);
return 0;
}
The output of the program is ______. (answer in
integer)
Note: Assume that the program compiles and runs
successfully.Consider the following C functions. The return value of fun2(5) is ____
The output after executing the following program is
___
#include <stdio.h>
int total(int v) {
while (v) {
static int count += v & 1;
v >>= 1;
}
return count;
}
void main() {
static int x = 0;
int i = 5;
for (; i > 0; i--) {
x = x + total(i);
}
printf("%d\n", x);
}void count(int n){
static int d = 1;
printf("%d ", n);
printf("%d ", d);
d++;
if(n > 1) count(n - 1);
printf("%d ", d);
}
void main(){
count(3);
}- (a)312213444
- (b)312111222
- (c)3122134
- (d)3121112
Consider the following C program. The output of the
program is __________.
# include <stdio.h>
int f1(void);
int f2(void);
int f3(void);
int x = 10;
int main()
{
int x = 1;
x += f1() + f2() + f3() + f2();
printf("%d", x);
return 0;
}
int f1()
{
int x = 25;
x++;
return x;
}
int f2( )
{
static int x = 50;
x++;
return x;
}
int f3( )
{
x *= 10;
return x;
}Consider the following C code segment.
int a, b, c = 0;
void prtFun (void);
main ()
{
static int a = 1;
prtFun ();
a + = 1;
prtFun ();
printf("\n %d %d ", a, b);
}
void prtFun (void)
{
static int a = 2;
int b = 1;
a + = + + b;
printf (" \n %d %d ", a, b);
}
What output will be generated by the given code
segment?- (a)31 41 42
- (b)42 61 61
- (c)42 62 20
- (d)42 42 20
Self-check
Question 1
What does this print?
#include <stdio.h>
int count(void) {
static int c = 0;
return ++c;
}
int main(void) {
int a = count();
int b = count();
int c = count();
printf("%d %d %d\n", a, b, c);
return 0;
}Show answerHide
The static c inside count survives; the c in main is a different variable.
1 2 3Question 2
Can a function return a pointer to its static local variable safely? What about to an ordinary local?
Show answerHide
A static local exists for the whole run, so a pointer to it stays valid. An ordinary local is destroyed when the function returns, so a pointer to it is dangling and using it is undefined.
Question 3
What does this print, and why is the answer not 5?
#include <stdio.h>
int v = 1;
void bump(void) {
int v = 5;
v = v + 1;
}
int main(void) {
bump();
printf("%d\n", v);
return 0;
}Show answerHide
The local v in bump hides the global, so bump only changes its own copy. The global is untouched:
1Question 4
Under dynamic scoping, in the pseudocode of Example 5, what would call f() print if g is changed to set x = 2 without the word local?
Show answerHide
Then g modifies the one and only (global) x, so both f calls print 2 under either scoping rule. The difference between the two scoping rules only appears when a local declaration shadows a global one.
Revision card
One-screen revision
- Scope is textual, lifetime is run-time, linkage is across files. Keep them separate.
- Automatic locals: new per call, garbage by default. Static and global: one copy, zero by default, initialised once.
staticlocal = local name, global lifetime.staticat file scope = private to the file.extern int x;declares only (with an initialiser it defines).registerforbids&.- Inner names shadow outer ones; C chooses by text (static scoping).
- Dynamic scoping looks along the call chain and gives different answers when a local shadows a global.
References
- ·Kernighan and Ritchie, The C Programming Language, 2nd ed., Sections 1.10 External Variables and Scope, 4.3 External Variables, 4.4 Scope Rules, 4.6 Static Variables, 4.7 Register Variables, 4.8 Block Structure, 4.9 Initialization
- ·ISO/IEC 9899:2011 (C11), Sections 6.2.1 Scopes of identifiers, 6.2.2 Linkages of identifiers, 6.2.4 Storage durations of objects, 6.5.3.2 Address and indirection operators, 6.7.1 Storage-class specifiers, 6.7.9 Initialization, 6.9 External definitions
- ·Aho, Lam, Sethi, Ullman, Compilers: Principles, Techniques, and Tools, 2nd ed., Section 1.6.3 Static Scope and Block Structure, Section 1.6.5 Dynamic Scope
Verification
The animation replays a real run of an instrumented C program (every value is read from memory at each step). All C programs on this page are compiled and run by npm run verify:c. The dynamic-scoping example was checked by running the same function structure in bash, which uses dynamic scoping. The prose, the linkage rules and the GATE-pattern claims have NOT yet had a human textbook check (the independent second pass is described at the end of these notes). SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand (long C programs were not re-read line by line: they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose). No defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)