#include <stdio.h>
void count_calls(void) {
// static local variable
static int count = 0;
count++;
printf("%d times\n", count);
}
int main(void) {
count_calls(); // First call
count_calls(); // Second call
count_calls(); // Third call
return 0;
}
called 1 times
called 2 times
called 3 times
Scope:
The count variable is declared inside the count_calls() function, so its scope is limited to this function. It cannot be accessed or modified directly outside of this function.
Lifetime:
The lifetime of the static variable count begins when the program starts, and it remains in memory until the program terminates. Its value persists between function calls.
int* dangling_pointer(void) {
int x = 5; /
return &x;
}
int main(void) {
int *ptr = dangling_pointer();
// ptr points to a local variable that no longer exists
printf("%d\n", *ptr);
// Undefined behavior: accessing a variable after its lifetime
return 0;
}
The behavior to access the return value of dangling_pointer() in the main function is undefined since the variable x's lifetime has ended before the dangling_pointer return to its caller main.
#include <stdio.h>
int global_x = 42;
void foo(void) {
// local scope of foo() begins
printf("%d\n", global_x);
}
int main(void) {
foo();
return 0;
}
#include <stdio.h>
void modify_value(int *ptr) {
*ptr = 20;
printf("%d\n", *ptr);
}
int main(void) {
int x = 10;
modify_value(&x);
printf("%d\n", x);
return 0;
}
When scopes overlap, the declaration in the inner scope hides the declaration from the outer scope.
if, switch, for, while, do-while statements, and the parameter list of a function definition.
int f(int n, int a[n]);int a; // file scope of name a begins here
void f(void){
int a = 1; // the block scope of the name a begins here;
// hides file-scope a
{
int a = 2;
// the scope of the inner a begins here, outer a is hidden
printf("%d\n", a); // inner a is in scope, prints 2
} // the block scope of the inner a ends here
printf("%d\n", a); // the outer a is in scope, prints 1
} // the scope of the outer a ends here
void g(int a);
// name a has function prototype scope; hides file-scope a;
// a is just a placeholder and is not accessible outside the prototype
static block-scope objects, etc.static, etc.| Type | Example | Scope | Duration |
|---|---|---|---|
| Local variable | int x; |
Block | Automatic |
| Static local variable | static int s_x; |
Block | Static |
| Function parameter | void foo(int x) |
Block | Automatic |
| Internal global variable | static int g_x; |
File | Static |
| External global variable | int g_x; |
File | Static |
Linkage refers to the ability of an identifier (variable or function) to be referenced in other scopes. The following types of linkage are recognized:
No linkage: The identifier can only be referenced from within its own scope.
extern block-scope variables (including the ones declared static).Internal linkage: The identifier can be referenced within the current translation unit.
static file-scope identifiers (both functions and variables).External linkage: The identifier can be referenced from any other translation units.
static functions, all extern variables (unless earlier declared static), and all file-scope non-static variables.In a C program with multiple source files, each file is compiled one at a time and linked into a single executable.
Until the compilation process, the scope of a variable defines its visibility and accessibility.

| Type | Example | Scope | Duration | Linkage |
|---|---|---|---|---|
| Local variable | int x; |
Block | Automatic | None |
| Static local variable | static int s_x; |
Block | Static | None |
| Function parameter | void foo(int x) |
Block | Automatic | None |
| Internal global variable | static int g_x; |
File | Static | Internal |
| External global variable | int g_x; |
File | Static | External |
CppReference:
If a variable or function with the same identifier is declared in several scopes, but cannot be referred to from all of them, then several instances of the variable are generated.
static Keyword#include <stdio.h>
void counter() {
static int count = 0;
count++;
printf("%d\n", count);
}
int main(void) {
counter(); // Output: 1
counter(); // Output: 2
counter(); // Output: 3
return 0;
}
#include <stdio.h>
// File-scope static variable
static int file_scope_var = 42;
// File-scope static function
static void file_scope_function(void){
printf("%d\n", file_scope_var);
}
int main(void){
file_scope_function();
return 0;
}
extern keywordThe extern specifier specifies static storage duration and external linkage. It can be used with function and object declarations in both file and block scope.
externFile1: file1.c
#include <stdio.h>
// Definition of a global variable
int shared_variable = 42;
void display_variable(void) {
printf("%d\n", shared_variable);
}
file1.c, shared_variable is defined as a global variable.file2.c, we declare it using extern, which allows us to access and modify shared_variable from file1.c.File2: file2.c
#include <stdio.h>
extern int shared_variable;
void display_variable(void);
void modify_variable(void) {
// Modifying the external variable
shared_variable = 100;
}
int main(void) {
modify_variable();
printf("%d\n", shared_variable);
return 0;
}
Output:
42
100
externFile1: file1.c
#include <stdio.h>
// Definition of a global variable
int shared_variable = 42;
void function_with_extern() {
// Declaration within block scope
extern int shared_variable;
// Block scope access
printf("%d\n", shared_variable);
}
File2: file2.c
// Declaration of the external variable
extern int shared_variable;
void function_with_extern(void);
int main() {
// accesses the variable
function_with_extern();
return 0;
}
Output: 42.
extern can also be used to declrations of block scope.externFile1: file1.c
#include <stdio.h>
static int shared_variable = 42;
void display_variable(void) {
printf("%d\n", shared_variable);
}
File2: file2.c
extern int shared_variable;
void display_variable(void);
void modify_variable(void) {
shared_variable = 100;
}
int main(void) {
modify_variable();
return 0;
}
error: linker failed; symbol(s) not found.
If a variable is declared without explicit initialization:
static variables) are initialized to indeterminate values. In other words, they are uninitialized.static variables), they are empty-initialized (called zero-initialization in C++):
0.0.0).#include <stdio.h>
int main(void){
n += 5;
printf("%d\n", n);
return 0;
}
#include <stdio.h>
int n = 0;
int main(void) {
n += 5;
printf("%d\n", n);
return 0;
}
#include <stdio.h>
int n = 0;
int main(void) {
int n;
n += 5;
printf("%d\n", n);
return 0;
}
#include <stdio.h>
int n = 0;
int main(void){
int n = 1;
n += 5;
printf("%d\n", n);
return 0;
}
#include <stdio.h>
int n = 0;
int main(void) {
extern int n;
n += 5;
printf("%d\n", n);
return 0;
}
#include <stdio.h>
int total(int x) {
static int total = 0;
total += x;
return total;
}
int main(void) {
total(5);
total(10);
printf("%d\n", total(15));
return 0;
}
library.h:
#ifndef LIBRARY_H
#define LIBRARY_H
int net_price(int price, int discount);
static int validate(int n);
#endif
driver.c:
#include "library.h"
int main(void) {
int i, j;
i = validate(-5);
j = net_price(6, 2);
}
library.c:
#include "library.h"
int net_price(int price, int discount) {
return validate(price - discount);
}
static int validate(int n) {
if (n < 0)
return 0;
else
return n;
}
account.h:
#ifndef ACCOUNT_H
#define ACCOUNT_H
#define ACCT_OK 0
#define ACCT_INVALID 1
#define ACCT_CLOSED 2
int acct_status;
#endif
account.c:
#include "account.h"
// Use acct_status
driver.c:
#include "account.h"
// Use acct_status
account.h:
#ifndef ACCOUNT_H
#define ACCOUNT_H
#define ACCT_OK 0
#define ACCT_INVALID 1
#define ACCT_CLOSED 2
// Don't define acct_status
// since that caused the problem
#endif
account.c:
#include "account.h"
// Use acct_status
driver.c:
#include "account.h"
// Use acct_status
account.h:
#ifndef ACCOUNT_H
#define ACCOUNT_H
#define ACCT_OK 0
#define ACCT_INVALID 1
#define ACCT_CLOSED 2
// Don't define acct_status
#endif
account.c:
#include "account.h"
int acct_status;
// Use acct_status
driver.c:
#include "account.h"
// Use acct_status
account.h:
#ifndef ACCOUNT_H
#define ACCOUNT_H
#define ACCT_OK 0
#define ACCT_INVALID 1
#define ACCT_CLOSED 2
extern int acct_status;
#endif
account.c:
#include "account.h"
// Use acct_status
driver.c:
#include "account.h"
// Use acct_status
account.h:
#ifndef ACCOUNT_H
#define ACCOUNT_H
#define ACCT_OK 0
#define ACCT_INVALID 1
#define ACCT_CLOSED 2
extern int acct_status;
#endif
account.c:
#include "account.h"
int acct_status = ACCT_OK;
// Use acct_status
driver.c:
#include "account.h"
// Use acct_status