Introduction
Storage classes in C define the scope, visibility, and lifetime of variables and functions. They determine where variables are stored in memory, how long they exist, and which parts of the program can access them. Understanding storage classes is essential for memory management and program organization.
Key Concepts
Scope: Region of program where variable can be accessed Lifetime: Duration for which variable exists in memory Linkage: Relationship between variable names in different source files Storage Duration: How long variable remains in memory Visibility: Which parts of program can see the variable Memory Location: Where variable is stored (stack, heap, data segment)
Types of Storage Classes
1. Auto Storage Class
Basic Auto Variables
#include <stdio.h>
void demonstrateAuto() {
// 'auto' keyword is optional - local variables are auto by default
auto int x = 10; // Explicit auto declaration
int y = 20; // Implicit auto (same as above)
printf("Auto variables: x = %d, y = %d\n", x, y);
printf("Address of x: %p\n", (void*)&x);
printf("Address of y: %p\n", (void*)&y);
// Auto variables are created when function is called
// and destroyed when function exits
}
void autoLifetimeDemo() {
for (int i = 0; i < 3; i++) {
auto int counter = 0; // Created fresh each iteration
counter++;
printf("Iteration %d: counter = %d\n", i, counter);
// counter is destroyed at end of each iteration
}
}
int main() {
printf("Auto Storage Class Demo:\n");
demonstrateAuto();
printf("\nAuto Lifetime Demo:\n");
autoLifetimeDemo();
return 0;
}
Auto Variables in Different Scopes
#include <stdio.h>
void nestedScopeDemo() {
int outer = 100; // Auto variable in function scope
printf("Outer scope: outer = %d\n", outer);
{
int inner = 200; // Auto variable in block scope
printf("Inner scope: inner = %d, outer = %d\n", inner, outer);
{
int deeper = 300; // Auto variable in deeper scope
printf("Deeper scope: deeper = %d, inner = %d, outer = %d\n",
deeper, inner, outer);
// deeper destroyed here
}
// printf("deeper = %d\n", deeper); // Error: deeper not accessible
// inner destroyed here
}
// printf("inner = %d\n", inner); // Error: inner not accessible
printf("Back to outer scope: outer = %d\n", outer);
// outer destroyed when function exits
}
int main() {
nestedScopeDemo();
return 0;
}
2. Static Storage Class
Static Local Variables
#include <stdio.h>
void staticLocalDemo() {
static int counter = 0; // Initialized only once
int regular = 0; // Initialized every call
counter++;
regular++;
printf("Static counter: %d, Regular: %d\n", counter, regular);
printf("Address of static counter: %p\n", (void*)&counter);
}
void functionCallCounter() {
static int callCount = 0;
callCount++;
printf("This function has been called %d times\n", callCount);
}
int main() {
printf("Static Local Variables Demo:\n");
for (int i = 0; i < 5; i++) {
staticLocalDemo();
}
printf("\nFunction Call Counter Demo:\n");
for (int i = 0; i < 3; i++) {
functionCallCounter();
}
return 0;
}
Static Global Variables
#include <stdio.h>
// Static global variable - visible only in this file
static int globalCounter = 0;
static char message[] = "File-specific data";
// Static function - internal linkage
static void internalFunction() {
printf("This is an internal function\n");
globalCounter++;
}
// Regular global function - external linkage
void externalFunction() {
printf("This is an external function\n");
internalFunction(); // Can call static function within same file
}
void displayGlobalCounter() {
printf("Global counter: %d\n", globalCounter);
printf("Message: %s\n", message);
}
int main() {
printf("Static Global Variables Demo:\n");
displayGlobalCounter();
externalFunction();
displayGlobalCounter();
internalFunction(); // Can call static function in same file
displayGlobalCounter();
return 0;
}
3. Register Storage Class
Register Variables Usage
#include <stdio.h>
void registerDemo() {
register int fastCounter; // Suggest storing in CPU register
register int i; // Loop variable - good candidate for register
printf("Register Variables Demo:\n");
// Registers are typically used for frequently accessed variables
for (i = 0; i < 1000000; i++) {
fastCounter = i * 2;
// Intensive computation where register access is beneficial
}
printf("Final value: %d\n", fastCounter);
// Note: Cannot take address of register variables
// printf("Address: %p\n", &fastCounter); // This would cause error
}
void registerVsAuto() {
auto int autoVar = 0;
register int regVar = 0;
printf("Comparing auto vs register:\n");
printf("Auto variable: %d (address: %p)\n", autoVar, (void*)&autoVar);
printf("Register variable: %d\n", regVar);
// printf("Register address: %p\n", ®Var); // Error: can't get address
}
int main() {
registerDemo();
registerVsAuto();
return 0;
}
4. Extern Storage Class
Extern Variable Declarations
// File 1: main.c
#include <stdio.h>
// Declare external variables (defined in other files)
extern int sharedData;
extern char sharedMessage[];
extern void externalUtility();
// Define global variables for this file
int localData = 100;
int main() {
printf("Extern Storage Class Demo:\n");
printf("Shared data: %d\n", sharedData);
printf("Shared message: %s\n", sharedMessage);
printf("Local data: %d\n", localData);
externalUtility();
// Modify external variable
sharedData = 999;
printf("Modified shared data: %d\n", sharedData);
return 0;
}
// File 2: external.c (conceptual - would be separate file)
/*
#include <stdio.h>
// Define the external variables
int sharedData = 42;
char sharedMessage[] = "Hello from external file";
void externalUtility() {
printf("External utility function called\n");
printf("Accessing shared data from external file: %d\n", sharedData);
}
*/
Extern Function Declarations
#include <stdio.h>
// External function declarations
extern int calculateSum(int a, int b);
extern void printResult(int result);
// Functions defined elsewhere (conceptually)
int calculateSum(int a, int b) {
return a + b;
}
void printResult(int result) {
printf("Result: %d\n", result);
}
int main() {
printf("External Function Demo:\n");
int sum = calculateSum(15, 25);
printResult(sum);
return 0;
}
Storage Class Comparison
Memory Location and Lifetime
#include <stdio.h>
#include <stdlib.h>
// Global variables (static storage duration)
int global = 1000;
static int staticGlobal = 2000;
void memoryLocationDemo() {
// Auto variables (automatic storage duration - stack)
int autoVar = 100;
char autoArray[100];
// Static local variable (static storage duration - data segment)
static int staticLocal = 300;
// Register variable (automatic storage duration - possibly register)
register int regVar = 400;
// Dynamic allocation (heap)
int *heapVar = malloc(sizeof(int));
*heapVar = 500;
printf("Memory Locations:\n");
printf("Global variable: %p (data segment)\n", (void*)&global);
printf("Static global: %p (data segment)\n", (void*)&staticGlobal);
printf("Auto variable: %p (stack)\n", (void*)&autoVar);
printf("Auto array: %p (stack)\n", (void*)autoArray);
printf("Static local: %p (data segment)\n", (void*)&staticLocal);
printf("Heap variable: %p (heap)\n", (void*)heapVar);
// printf("Register variable: %p\n", (void*)®Var); // Error: no address
printf("\nValues:\n");
printf("Global: %d\n", global);
printf("Static global: %d\n", staticGlobal);
printf("Auto: %d\n", autoVar);
printf("Static local: %d\n", staticLocal);
printf("Register: %d\n", regVar);
printf("Heap: %d\n", *heapVar);
free(heapVar);
}
int main() {
memoryLocationDemo();
return 0;
}
Scope and Visibility Rules
#include <stdio.h>
// File scope variables
int fileScope = 100;
static int fileStatic = 200;
void functionA() {
printf("Function A:\n");
printf(" File scope: %d\n", fileScope); // Accessible
printf(" File static: %d\n", fileStatic); // Accessible
static int funcStatic = 300;
funcStatic++;
printf(" Function static: %d\n", funcStatic);
}
void functionB() {
printf("Function B:\n");
printf(" File scope: %d\n", fileScope); // Accessible
printf(" File static: %d\n", fileStatic); // Accessible
// printf(" Function static: %d\n", funcStatic); // Error: not accessible
int localVar = 400;
printf(" Local variable: %d\n", localVar);
}
void scopeDemo() {
int x = 10;
printf("Outer scope: x = %d\n", x);
{
int x = 20; // Shadows outer x
printf("Inner scope: x = %d\n", x);
{
int x = 30; // Shadows both outer x values
printf("Innermost scope: x = %d\n", x);
}
printf("Back to inner scope: x = %d\n", x);
}
printf("Back to outer scope: x = %d\n", x);
}
int main() {
printf("Scope and Visibility Demo:\n\n");
functionA();
functionA(); // Notice static variable retains value
functionB();
printf("\nShadowing Demo:\n");
scopeDemo();
return 0;
}
Advanced Storage Class Concepts
Initialization Behavior
#include <stdio.h>
// Global variables are automatically initialized to zero
int uninitGlobal; // Initialized to 0
static int uninitStatic; // Initialized to 0
void initializationDemo() {
// Auto variables are NOT automatically initialized
int uninitAuto; // Contains garbage value
static int uninitLocalStatic; // Initialized to 0
// Initialized variables
int initAuto = 42;
static int initStatic = 100;
printf("Initialization Demo:\n");
printf("Uninitialized global: %d\n", uninitGlobal);
printf("Uninitialized static: %d\n", uninitStatic);
printf("Uninitialized local static: %d\n", uninitLocalStatic);
printf("Initialized auto: %d\n", initAuto);
printf("Initialized static: %d\n", initStatic);
// Warning: Don't print uninitialized auto variables in real code
// printf("Uninitialized auto: %d\n", uninitAuto); // Garbage value
}
int main() {
initializationDemo();
return 0;
}
Storage Class with Arrays and Pointers
#include <stdio.h>
#include <stdlib.h>
// Static array with file scope
static int staticArray[5] = {1, 2, 3, 4, 5};
void arrayStorageDemo() {
// Auto array (stack)
int autoArray[5] = {10, 20, 30, 40, 50};
// Static local array (data segment)
static int staticLocalArray[5] = {100, 200, 300, 400, 500};
// Dynamic array (heap)
int *dynamicArray = malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) {
dynamicArray[i] = (i + 1) * 1000;
}
printf("Array Storage Demo:\n");
printf("Static array (file scope): ");
for (int i = 0; i < 5; i++) {
printf("%d ", staticArray[i]);
}
printf("(Address: %p)\n", (void*)staticArray);
printf("Auto array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", autoArray[i]);
}
printf("(Address: %p)\n", (void*)autoArray);
printf("Static local array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", staticLocalArray[i]);
}
printf("(Address: %p)\n", (void*)staticLocalArray);
printf("Dynamic array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", dynamicArray[i]);
}
printf("(Address: %p)\n", (void*)dynamicArray);
free(dynamicArray);
}
int main() {
arrayStorageDemo();
return 0;
}
Best Practices
- Use auto for local variables that don’t need to persist
- Use static for persistent local state or file-private globals
- Use extern sparingly and prefer function parameters/return values
- Avoid register unless performance profiling shows benefit
- Initialize variables explicitly rather than relying on defaults
- Minimize global variable usage to improve code maintainability
- Use appropriate scope - declare variables in smallest necessary scope
- Document external dependencies clearly in header files
Common Applications
Singleton Pattern with Static
#include <stdio.h>
typedef struct {
int id;
char name[50];
} Config;
Config* getConfig() {
static Config instance = {1, "System Configuration"};
static int initialized = 0;
if (!initialized) {
printf("Initializing configuration...\n");
initialized = 1;
}
return &instance;
}
int main() {
Config *config1 = getConfig();
Config *config2 = getConfig();
printf("Config 1: %p\n", (void*)config1);
printf("Config 2: %p\n", (void*)config2);
printf("Same instance: %s\n", (config1 == config2) ? "Yes" : "No");
return 0;
}
Summary
Storage classes in C (auto, static, register, extern) control variable scope, lifetime, and memory location. Auto variables have automatic storage duration and local scope. Static variables have static storage duration and maintain values between function calls. Register variables are hints for compiler optimization. Extern variables provide linkage between different source files. Understanding storage classes is essential for proper memory management and program organization.
Part of BCA Programming with C Course (UGCOA22J201)