Docs

README

Scope and Storage Classes in C

Table of Contents

  1. •Introduction
  2. •What is Scope?
  3. •Types of Scope
  4. •Storage Classes
  5. •The auto Storage Class
  6. •The register Storage Class
  7. •The static Storage Class
  8. •The extern Storage Class
  9. •Scope vs Storage Class
  10. •Best Practices
  11. •Common Mistakes
  12. •Summary

Introduction

Understanding scope and storage classes is crucial for writing efficient, bug-free C programs. These concepts determine:

  • •Where a variable can be accessed (scope)
  • •How long a variable exists in memory (lifetime)
  • •Where a variable is stored (storage location)
  • •How a variable is initialized (default initialization)

What is Scope?

Scope defines the region of a program where a variable is visible and can be accessed. A variable cannot be accessed outside its scope.

Scope = Visibility + Accessibility

Why Scope Matters

  1. •Prevents naming conflicts - Same names can be used in different scopes
  2. •Encapsulation - Keeps variables private to their context
  3. •Memory efficiency - Variables are destroyed when out of scope
  4. •Code organization - Logical grouping of related variables

Types of Scope

1. Block Scope (Local Scope)

Variables declared inside a block { } are only accessible within that block.

void function() {
    int x = 10;         // x is visible from here

    if (x > 5) {
        int y = 20;     // y is only visible inside this if block
        printf("%d", y); // OK
    }

    // printf("%d", y);  // ERROR! y is out of scope
}

Visualization:

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ Function Scope                      │
│ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │
│ │ int x = 10;  ← visible here     │ │
│ │                                 │ │
│ │ ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”   │ │
│ │ │ if block                  │   │ │
│ │ │ int y = 20; ← only here   │   │ │
│ │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜   │ │
│ │                                 │ │
│ │ y not accessible here           │ │
│ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

2. Function Scope

Labels (used with goto) have function scope - they are visible throughout the entire function.

void function() {
    goto end;           // Can jump to label anywhere in function

    // ... code ...

    end:                // Label has function scope
        printf("End");
}

3. File Scope (Global Scope)

Variables declared outside all functions have file scope - they are accessible throughout the file.

#include <stdio.h>

int globalVar = 100;    // File scope - accessible everywhere

void function1() {
    printf("%d", globalVar);  // OK
}

void function2() {
    globalVar = 200;          // OK
}

4. Function Prototype Scope

Parameter names in function prototypes have scope only within the prototype.

void function(int x, int y);    // x, y only have meaning in prototype
// x and y names are forgotten here

Storage Classes

Storage classes define the lifetime, visibility, and storage location of variables.

Storage ClassKeywordDefault ValueScopeLifetimeStorage
AutomaticautoGarbageLocalBlockStack
RegisterregisterGarbageLocalBlockCPU Register
Staticstatic0Local/GlobalProgramData Segment
Externalextern0GlobalProgramData Segment

The auto Storage Class

Definition

  • •Default storage class for local variables
  • •Variables are created when block is entered, destroyed when exited
  • •Stored on the stack
  • •Must be initialized explicitly (contains garbage otherwise)

Syntax

auto int x;     // Explicitly auto (rarely used)
int x;          // Implicitly auto (common usage)

Characteristics

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│           AUTO VARIABLES            │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ Storage:      Stack                 │
│ Default:      Garbage value         │
│ Scope:        Block (local)         │
│ Lifetime:     Block execution       │
│ Visibility:   Within block only     │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Example

void demo() {
    auto int x = 10;    // Explicit (unnecessary)
    int y = 20;         // Implicit auto

    {
        int z = 30;     // Also auto, inner block scope
    }
    // z is destroyed here
}
// x and y are destroyed here

When to Use

  • •Always used by default for local variables
  • •Explicit auto keyword is rarely needed (C99+)

The register Storage Class

Definition

  • •Suggests storing variable in CPU register for faster access
  • •No memory address (cannot use & operator)
  • •Modern compilers often ignore this hint (they optimize better)

Syntax

register int counter;
register int i;

Characteristics

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│        REGISTER VARIABLES           │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ Storage:      CPU Register (hint)   │
│ Default:      Garbage value         │
│ Scope:        Block (local)         │
│ Lifetime:     Block execution       │
│ Address:      Cannot use & operator │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Example

void loop_demo() {
    register int i;     // Request register storage

    for (i = 0; i < 1000000; i++) {
        // Fast loop counter access
    }

    // int *ptr = &i;   // ERROR! Cannot take address
}

Limitations

  1. •Cannot use address-of operator (&)
  2. •Limited number of registers available
  3. •Compiler may ignore the request
  4. •Cannot be global variables

When to Use

  • •Loop counters accessed frequently
  • •Variables in performance-critical code
  • •Note: Modern compilers auto-optimize, making this less useful

The static Storage Class

Definition

  • •Variable persists for entire program execution
  • •Initialized only once
  • •Default value is 0 (or NULL for pointers)
  • •Can be local (static local) or global (static global)

Two Uses of Static

1. Static Local Variables

void counter() {
    static int count = 0;   // Initialized only once
    count++;
    printf("Count: %d\n", count);
}

int main() {
    counter();  // Count: 1
    counter();  // Count: 2
    counter();  // Count: 3
    return 0;
}

2. Static Global Variables

static int fileLocal = 100;  // Only visible in this file

void function() {
    printf("%d", fileLocal);  // OK
}

// Other files cannot access fileLocal

Characteristics

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│         STATIC VARIABLES            │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ Storage:      Data Segment          │
│ Default:      0 (zero)              │
│ Scope:        Local or File         │
│ Lifetime:     Entire program        │
│ Initialization: Once only           │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Memory Visualization

Stack (auto variables)
ā”œā”€ā”€ function1 local vars
ā”œā”€ā”€ function2 local vars
└── ...

Data Segment (static variables)
ā”œā”€ā”€ static int x = 10;     ← Persists here
ā”œā”€ā”€ static int count = 0;  ← Persists here
└── ...

Static vs Auto Comparison

void auto_demo() {
    int x = 0;          // Created each call
    x++;
    printf("%d ", x);   // Always prints 1
}

void static_demo() {
    static int x = 0;   // Created once
    x++;
    printf("%d ", x);   // Prints 1, 2, 3, ...
}

When to Use Static

  1. •Preserving state between function calls
  2. •Counting function invocations
  3. •Caching computed values
  4. •Limiting visibility of global variables to one file
  5. •Implementing singleton patterns

The extern Storage Class

Definition

  • •Declares a variable defined elsewhere (another file or later in same file)
  • •Used for sharing variables across multiple files
  • •Does not allocate memory (just references existing variable)

Syntax

extern int globalVar;    // Declaration (no memory allocated)

How extern Works

File1.c (Definition):

int sharedVar = 100;     // Definition - memory allocated

void modifyVar() {
    sharedVar = 200;
}

File2.c (Usage):

extern int sharedVar;    // Declaration - refers to File1's variable

void printVar() {
    printf("%d", sharedVar);  // Uses File1's sharedVar
}

Characteristics

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│         EXTERN VARIABLES            │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ Storage:      Data Segment          │
│ Default:      0 (at definition)     │
│ Scope:        Global (multiple files)│
│ Lifetime:     Entire program        │
│ Purpose:      Cross-file sharing    │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Declaration vs Definition

AspectDeclarationDefinition
MemoryNo allocationAllocates memory
KeywordUses externNo extern
InitializationCannot initializeCan initialize
CountMultiple allowedOnly one
extern int x;       // Declaration
int x = 10;         // Definition

extern int x;       // Another declaration (OK)
// int x = 20;      // ERROR! Redefinition

When to Use extern

  1. •Sharing globals across multiple source files
  2. •Organizing code into separate compilation units
  3. •Header files for variable declarations
  4. •Large projects with modular code structure

Best Practice with extern

globals.h:

#ifndef GLOBALS_H
#define GLOBALS_H

extern int globalCounter;
extern char programName[];

#endif

globals.c:

#include "globals.h"

int globalCounter = 0;
char programName[] = "MyProgram";

main.c:

#include "globals.h"

int main() {
    globalCounter++;
    printf("%s: %d\n", programName, globalCounter);
    return 0;
}

Scope vs Storage Class

Key Differences

AspectScopeStorage Class
DefinesWhere accessibleHow/where stored
FocusVisibilityLifetime & storage
TypesBlock, File, Functionauto, register, static, extern

Combined Effects

// Global static: file scope, static storage
static int fileGlobal = 10;

void function() {
    // Local auto: block scope, auto storage
    int localAuto = 20;

    // Local static: block scope, static storage
    static int localStatic = 30;

    // Local register: block scope, register storage
    register int localRegister = 40;
}

Visualization

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                    MEMORY LAYOUT                   │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                    │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │ Code Segment (Text)                          │  │
│  │ - Program instructions                       │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
│                                                    │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │ Data Segment                                 │  │
│  │ - Global variables                           │  │
│  │ - Static variables (global and local)        │  │
│  │ - extern variables                           │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
│                                                    │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │ Stack                                        │  │
│  │ - auto (local) variables                     │  │
│  │ - Function parameters                        │  │
│  │ - Return addresses                           │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
│                                                    │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │ Heap                                         │  │
│  │ - Dynamically allocated memory               │  │
│  │ - malloc(), calloc(), realloc()              │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
│                                                    │
│  ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”  │
│  │ CPU Registers                                │  │
│  │ - register variables (if granted)            │  │
│  ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜  │
│                                                    │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Best Practices

1. Minimize Global Variables

// BAD: Too many globals
int count, total, average, min, max;

// GOOD: Use local variables, pass as parameters
void calculate(int data[], int size, int *total, int *avg) {
    // ...
}

2. Use Static for File-Private Variables

// File: calculator.c
static int operationCount = 0;  // Private to this file

void calculate() {
    operationCount++;
}

3. Prefer auto Over register

// Let the compiler decide optimization
int i;              // GOOD: Compiler optimizes

// register int i;  // OK but usually unnecessary

4. Initialize Static Variables Explicitly

static int count;       // OK (defaults to 0)
static int count = 0;   // BETTER (explicit)

5. Use extern in Header Files

// In header file
extern int sharedData;

// In one .c file
int sharedData = 0;

Common Mistakes

1. Accessing Out-of-Scope Variables

void function() {
    if (1) {
        int x = 10;
    }
    // printf("%d", x);  // ERROR! x out of scope
}

2. Shadowing Variables

int x = 10;             // Global

void function() {
    int x = 20;         // Shadows global x (confusing!)
    printf("%d", x);    // Prints 20, not 10
}

3. Forgetting Static Persistence

void counter() {
    static int count = 0;
    count++;
    count = 0;          // BUG! Resets every call (defeats static purpose)
}

4. Address of Register Variable

register int x = 10;
// int *ptr = &x;      // ERROR! Cannot take address

5. Multiple Definitions

// File1.c
int global = 10;

// File2.c
int global = 20;        // ERROR! Multiple definitions

// Correct in File2.c:
extern int global;      // Declaration, not definition

Summary

Quick Reference Table

Featureautoregisterstaticextern
Default forLocal vars---
StorageStackCPU RegDataData
Initial ValueGarbageGarbage00
ScopeBlockBlockBlock/FileGlobal
LifetimeBlockBlockProgramProgram
Address (&)YesNoYesYes
Multi-fileNoNoNoYes

Decision Flowchart

Need a variable?
      │
      ā”œā”€ā”€ Local only, temporary?
      │         │
      │         └── Use auto (default)
      │
      ā”œā”€ā”€ Local but persist between calls?
      │         │
      │         └── Use static local
      │
      ā”œā”€ā”€ Global but one file only?
      │         │
      │         └── Use static global
      │
      └── Global across multiple files?
                │
                └── Use extern (declare) + definition

Key Points to Remember

  1. •auto - Default for locals, stack storage, block lifetime
  2. •register - Hint for CPU register, cannot take address
  3. •static local - Persists between calls, initialized once
  4. •static global - Limits visibility to file
  5. •extern - References variable defined elsewhere
  6. •Scope ≠ Lifetime - A variable can outlive its scope (static)

Next Steps

After mastering scope and storage classes:

  1. •Practice with multi-file programs
  2. •Understand memory layout of C programs
  3. •Learn about dynamic memory allocation
  4. •Study function pointers and callbacks

"The scope of a variable should be as small as possible, and the lifetime as short as necessary." — Good Programming Practice

README - C Programming Tutorial | DeepML