Nearby lessons

110 of 124

C - auto Storage Class

auto is the default storage class for local variables — created on the stack when the block is entered, destroyed when it exits. Learn what it means, why nobody writes it, and how C++11 gave the same keyword a completely different job.

auto Is the Default

Every local variable is automatic whether you say so or not. These two declarations are identical:

Example01
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 auto int a = 10; /* explicitly automatic */
6 int b = 20; /* automatically automatic */
7 
8 printf("a = %d\n", a);
9 printf("b = %d\n", b);
10 printf("Identical in every way: sizeof %zu and %zu\n",
11 sizeof(a), sizeof(b));
12 return 0;
13}
Output
a = 10
b = 20
Identical in every way: sizeof 4 and 4

Automatic Lifetime

In simple words: "automatic" describes the memory management, not the value. The variable is automatically created when control reaches its declaration and automatically destroyed when the block ends — you never allocate or free it yourself.
Example02
CCode Cell
1#include <stdio.h>
2 
3void demo(void)
4{
5 int count = 0; /* created fresh on every call */
6 
7 count++;
8 printf("count = %d\n", count);
9} /* destroyed here */
10 
11int main()
12{
13 demo();
14 demo();
15 demo();
16 printf("Always 1 - each call gets a brand-new variable.\n");
17 return 0;
18}
Output
count = 1
count = 1
count = 1
Always 1 - each call gets a brand-new variable.

Block Scope, Block Lifetime

An automatic variable belongs to the innermost braces around it — not just to the function:

Example03
CCode Cell
1#include <stdio.h>
2 
3int main()
4{
5 int outer = 1;
6 
7 {
8 int inner = 2; /* born here */
9 printf("Inside : outer=%d inner=%d\n", outer, inner);
10 } /* dies here */
11 
12 /* printf("%d", inner); ERROR: out of scope */
13 
14 for (int i = 0; i < 3; i++)
15 {
16 int loopVar = i * 10; /* new one every iteration */
17 printf("i=%d loopVar=%d\n", i, loopVar);
18 }
19 
20 printf("outer is still %d\n", outer);
21 return 0;
22}
Output
Inside : outer=1 inner=2
i=0 loopVar=0
i=1 loopVar=10
i=2 loopVar=20
outer is still 1

No Automatic Initialisation

An automatic variable starts with garbage, and the garbage is often zero by accident. A fresh stack page really is zero-filled, so a program can appear to work perfectly in testing and then break the moment a new function call leaves different bytes behind. Never rely on it — initialise at declaration.
Example04
CCode Cell
1#include <stdio.h>
2 
3void leaveMess(void)
4{
5 int junk[4] = {111, 222, 333, 444}; /* writes onto the stack */
6 (void) junk;
7}
8 
9void readStack(void)
10{
11 int uninitialised[4]; /* same stack region */
12 for (int i = 0; i < 4; i++)
13 printf("%d ", uninitialised[i]); /* undefined behaviour */
14 printf("\n");
15}
16 
17int main()
18{
19 printf("Do NOT write code like this - it is undefined behaviour:\n");
20 leaveMess();
21 readStack(); /* may print the leftovers, may print anything */
22 
23 int safe = 0; /* the only correct approach */
24 printf("safe = %d\n", safe);
25 return 0;
26}
Output
Do NOT write code like this - it is undefined behaviour:
111 222 333 444
safe = 0

Only Valid Inside a Function

auto is meaningless at file scope, where variables have static lifetime by definition:

Example05
CCode Cell
1#include <stdio.h>
2 
3/* auto int global = 10; ERROR: file-scope declaration
4 specifies 'auto' */
5 
6int global = 10; /* correct - static lifetime, external linkage */
7 
8int main()
9{
10 auto int local = 20; /* legal here */
11 
12 printf("global = %d\n", global);
13 printf("local = %d\n", local);
14 return 0;
15}
Output
global = 10
local  = 20

auto vs static

The contrast is the whole point of the keyword. One resets, one remembers:

autostatic
Stored inStackData segment
CreatedOn every entryOnce, before main
DestroyedOn block exitWhen the program ends
Default valueGarbageZero
Keeps its value between callsNoYes
Safe with recursion / threadsYes — one per callNo — one shared copy
Example06
CCode Cell
1#include <stdio.h>
2 
3void compare(void)
4{
5 auto int a = 0;
6 static int s = 0;
7 
8 a++;
9 s++;
10 printf("auto=%d static=%d\n", a, s);
11}
12 
13int main()
14{
15 compare();
16 compare();
17 compare();
18 return 0;
19}
Output
auto=1  static=1
auto=1  static=2
auto=1  static=3

Why Automatic Variables Make Recursion Work

Each recursive call gets its own stack frame with its own copy of every automatic variable. That is precisely why recursion works at all:

Example07
CCode Cell
1#include <stdio.h>
2 
3int factorial(int n)
4{
5 int result; /* a separate 'result' per call */
6 
7 printf("Entering with n = %d\n", n);
8 
9 if (n <= 1)
10 result = 1;
11 else
12 result = n * factorial(n - 1);
13 
14 printf("Returning %d for n = %d\n", result, n);
15 return result;
16}
17 
18int main()
19{
20 printf("\n4! = %d\n", factorial(4));
21 return 0;
22}
Output
Entering with n = 4
Entering with n = 3
Entering with n = 2
Entering with n = 1
Returning 1 for n = 1
Returning 2 for n = 2
Returning 6 for n = 3
Returning 24 for n = 4

4! = 24

Never Return the Address of One

The variable is gone the instant the function returns, so its address is worthless:

Example08
CCode Cell
1#include <stdio.h>
2#include <stdlib.h>
3 
4/* BROKEN
5int *broken(void)
6{
7 int local = 42;
8 return &local; <- points at a destroyed stack frame
9}
10*/
11 
12int *works(void)
13{
14 static int persistent = 42; /* lives for the whole program */
15 return &persistent;
16}
17 
18int *alsoWorks(void)
19{
20 int *heap = malloc(sizeof(int)); /* the caller owns it */
21 if (heap != NULL) *heap = 42;
22 return heap;
23}
24 
25int main()
26{
27 printf("static : %d\n", *works());
28 
29 int *p = alsoWorks();
30 if (p != NULL) { printf("heap : %d\n", *p); free(p); }
31 return 0;
32}
Output
static : 42
heap   : 42

C's auto Is Not C++'s auto

The same keyword means two unrelated things in the two languages. In C it is a storage class that nobody writes. In C++11 and later it means "work out the type from the initialiser" — a genuinely useful feature. If you have seen auto x = 5; in C++ code, that is type deduction, not storage.
Example09
CCode Cell
1/* In C: auto is a storage class specifier */
2auto int x = 5; /* the type is int; auto adds nothing */
3 
4/* In C++11 and later: auto deduces the type */
5/* auto x = 5; x is deduced to be int
6 auto y = 3.14; y is deduced to be double
7 auto s = "text"; s is deduced to be const char * */
8 
9/* In C, 'auto x = 5;' without a type is invalid.
10 C23 does add type inference with auto, aligning with C++,
11 but no earlier C standard supports it. */
Output
Two different meanings for one keyword

Common Mistakes

  • Assuming automatic means initialised — it means automatically allocated, nothing more.
  • Reading an uninitialised local — undefined behaviour, even when it seems to print 0.
  • Returning the address of a local — the memory is reclaimed immediately.
  • Using auto at file scope — a compile error.
  • Expecting a local to remember its value — use static for that.
  • Declaring a huge array as a local — the stack is small; large buffers belong on the heap.
  • Reading C++ tutorials for C's auto — the keyword means something else there.
Trainer's Note: the practical takeaway is that you will never type auto in C. Its value is conceptual: knowing that your locals are automatic explains why they reset every call, why recursion has independent copies, why a 10 MB local array crashes, and why returning &local is a bug.
📝 Key Takeaways
  • auto is the default for every local variable — writing it changes nothing.
  • Automatic variables live on the stack and die when the block exits.
  • They are not zero-initialised; they hold garbage until you assign.
  • auto can only be used inside a function, never at file scope.
  • In C++11 and later, auto means "deduce the type" — a different keyword entirely.

🧠 Test Your Knowledge

4 Questions
Progress: 0 / 4