C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
12: Storage Classes: auto, static, extern, register
Think of your program's memory like a busy office space. Not every piece of information needs to be stored in the same way. Some things are just scribbles on a Post-it note that you toss in the trash the moment you finish a task. Other things are written on a whiteboard in a specific room; they stay there even if you leave the room and come back later. Then you have the company-wide bulletin board in the lobby—everyone in the building can see it, no matter which office they're in. Finally, there's the handheld calculator in your pocket; it's incredibly fast to access, but it can only hold one or two numbers at a time.
In C, storage classes are exactly that. They tell the compiler where to store a variable, how long it should live (lifetime), and who is allowed to see it (visibility/scope). Let's map those office tools to the actual keywords.
Ephemeral Notes and Permanent Whiteboards
Most variables you've written so far are auto. In fact, if you don't specify a storage class for a local variable, C assumes it's auto. Like a Post-it note, an auto variable is created when the function starts and is destroyed the second the function returns. It's "automatic" memory management at its simplest.
Now, static is where things get interesting. A static local variable is like that whiteboard. It's still only visible to the function it's in, but it doesn't disappear when the function ends. It remembers its value for the entire duration of the program. I use this all the time when I need a function to keep track of its own state without cluttering the global namespace.
#include <stdio.h>
void track_calls() {
auto int local_count = 0; // Re-initialized to 0 every time
static int static_count = 0; // Initialized once, persists between calls
local_count++;
static_count++;
printf("Local: %d, Static: %d\n", local_count, static_count);
}
int main() {
track_calls(); // Local: 1, Static: 1
track_calls(); // Local: 1, Static: 2
track_calls(); // Local: 1, Static: 3
return 0;
}
The Company Bulletin Board
When your project grows beyond a single .c file, you'll run into a problem: how does file_a.c access a variable defined in file_b.c? This is where extern comes in. It's the company bulletin board.
The key thing to remember here is that extern is a declaration, not a definition. You aren't telling the compiler to "create a new variable"; you're telling it, "Somewhere else in this project, a variable with this name and type already exists. Go find it."
If you define int global_score = 100; in one file and put extern int global_score; in another, both files are now looking at the exact same spot in memory. Just be careful—overusing extern turns your code into a tangled web of dependencies that's a nightmare to debug. Use it sparingly.
The Pocket Calculator
Finally, we have register. This is a hint to the compiler that you'll be using this variable a lot and it should be stored in a CPU register instead of RAM for lightning-fast access. It's like keeping a number in your head or on a handheld calculator rather than walking across the room to check the whiteboard.
Here's the catch: register is just a suggestion. Modern compilers are actually much better at optimizing register allocation than we are, so they often ignore this keyword entirely. Also, because a register isn't a memory address, you cannot use the & (address-of) operator on a register variable. If you try, the compiler will throw an error.
📋 Practical Task
Exercise: Persistent Session Tracker for a Game Menu
You are building a simple game menu system. You need to track two different things: the total number of times the "Settings" menu has been opened during the entire game session, and a global "Game Difficulty" level that can be accessed by different parts of the program.
Requirements:
- Create a function
void open_settings_menu(). Inside this function, use astaticvariable to keep track of how many times the menu has been opened. Each time the function is called, increment the counter and print:"Settings menu opened X times". - In your main file, define a global variable
int game_difficulty = 1;. - Create a second separate function (simulating a different module) called
void print_difficulty(). Use theexternkeyword within this function's scope (or above it) to access and print thegame_difficultyvariable. - In
main(), callopen_settings_menu()three times and callprint_difficulty()once to verify everything is working as expected.
There are no comments for now.