October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk6 min

Heap vs Stack Memory in C: Storage Duration, Lifetime, and malloc

C defines automatic and allocated storage durations, not stack and heap. Learn when each object's lifetime ends, what malloc returns, and which common claims are wrong.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

In C, the useful distinction is not “stack versus heap” but automatic storage duration versus allocated storage duration. Automatic objects end their lifetime when the block that declares them exits. Allocated objects last until your program deallocates or reallocates them. “Stack” and “heap” are the names most implementations use for these two behaviors, but the C language does not require either term to describe physical memory.

Why the terminology matters

C defines four storage durations: automatic, static, thread, and allocated. The standard’s rules are written in terms of when an object’s lifetime begins and ends, and who is responsible for ending it. Nothing in those rules says where the bytes live. A typical implementation places automatic objects in a call stack and allocated objects in a heap, which is why the two names stuck, but a compiler or platform may choose other layouts as long as the observable behavior matches the standard. The distinction matters because a bug that depends on the implementation model (for example, an address that happens to still hold a value) is still a bug under the language rules.

As an Amazon Associate I earn from qualifying purchases.

The rest of this article uses the standard’s terms, with “stack” and “heap” shown as common shorthand.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Automatic storage: the “stack” case

Non-static objects declared inside a block, and function parameters, generally have automatic storage duration. Storage is set up when the declaring block is entered and released when that block exits. Each recursive call gets its own separate set of these objects, so the recursion depth determines how many distinct copies exist at once.

Variable-length arrays follow a slightly different rule: their storage is allocated when the declaration is executed and released when the declaration goes out of scope. Automatic objects are the default choice for values whose useful life matches a function call or a block. You do not call any function to create or destroy them, and you cannot free them early. The storage-duration reference describes these rules in detail.

The dangling-pointer trap

Automatic lifetime has one consequence that catches many learners. A pointer to an automatic object becomes invalid when the object’s block ends, and the pointer does not extend the object’s life. Consider this function:

int *make_value(void)
{
    int local = 42;
    return &local;   /* local's lifetime ends when the function returns */
}

int main(void)
{
    int *p = make_value();
    printf("%dn", *p);   /* undefined behavior: p refers to an object whose lifetime has ended */
    return 0;
}

The program may print 42 on one compiler and crash or print garbage on another, and either outcome is consistent with the standard. The lifetime reference uses this same kind of example to show dereferencing after the object’s lifetime has ended. Returning the value of local would be fine; returning its address is the error.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Allocated storage: the “heap” case

Allocated storage is requested at run time through the allocation functions in the standard library. The main ones are malloc, calloc, and realloc. Storage is released with free, or resized with realloc. The object’s lifetime begins when the allocation function returns and ends when it is reallocated or deallocated. Because the lifetime is controlled by the program rather than by a block, the memory can outlive the function that created it.

That freedom comes with explicit responsibility. The program must keep track of every pointer that refers to the allocation, check whether the request succeeded, and release the storage exactly when it is no longer needed.

What malloc returns

According to the malloc reference, malloc allocates uninitialized storage. On success it returns a pointer suitably aligned for any object type with fundamental alignment. On failure it returns a null pointer. A correct allocation therefore has three steps: request the memory, check the return value, and only then use it.

int *make_value(void)
{
    int *p = malloc(sizeof *p);
    if (p == NULL) {
        return NULL;     /* allocation failed; the caller must handle this */
    }
    *p = 42;             /* the storage is uninitialized until assigned */
    return p;            /* ownership passes to the caller */
}

Two details deserve emphasis. First, malloc does not zero the memory, so reading it before writing is an error. Second, the returned pointer is the only route to the storage. If you overwrite it or let it go out of scope without calling free, the memory is leaked for the rest of the program’s run.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Static and thread storage

Not every object is either automatic or allocated. File-scope objects and objects declared with static have static storage duration and last for the entire program execution. Objects declared _Thread_local have thread storage duration and last for the life of their thread. Both categories are described in the storage-duration reference. Treating C memory as a simple two-way choice leaves out a large part of how real programs store global state.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Comparing the two durations

Question Automatic storage (“stack”) Allocated storage (“heap”)
When does the lifetime start? When the declaring block is entered When the allocation function returns
When does the lifetime end? When the block exits (or the declaration goes out of scope for variable-length arrays) When the object is deallocated or reallocated
Who ends the lifetime? The language, automatically The program, by calling free or realloc
Can it outlive the function that created it? No; a pointer to it becomes invalid Yes, until it is released
Size known at compile time? Required for ordinary objects; variable-length arrays are the exception Not required; the size is chosen at run time
Initialization Set by the program; not stated as zeroed by the storage rules Uninitialized with malloc
Failure when obtaining storage Not a request-time failure in the same sense; the program does not ask for it Returns a null pointer on failure, which must be checked
Relative speed Not stated by the standard; no portable figure exists Not stated by the standard; no portable figure exists
Capacity limit Not stated by the standard; depends on the implementation and platform Not stated by the standard; depends on the implementation and platform

The speed and capacity rows are intentionally blank of numbers. The C standard does not establish either, and any specific figure would depend on a particular compiler, operating system, and configuration. If you need such numbers, measure them on the target system.

Choosing between them

  • Use automatic storage when the object is only needed while a function runs and its size is fixed at compile time. It is the simplest option, and the compiler handles cleanup.
  • Use allocated storage when the object must outlive the block that creates it, or when its size is known only at run time, such as a buffer read from a file.
  • Use static storage for values that should persist across calls to a function or across the whole program, and avoid sharing them across threads without synchronization.
  • Whichever you choose, make ownership explicit: name the function responsible for each allocation and document who frees it.

Common misconceptions to correct

  • “The C standard says local variables live on the stack.” The standard says they have automatic storage duration. The call stack is a common implementation model, not a requirement.
  • “A pointer is the heap object.” A pointer is an object in its own right. A local pointer variable has automatic duration even when it holds the address of allocated storage.
  • “Heap memory disappears when the function returns.” Allocated storage persists until it is deallocated. What ends when the function returns is the lifetime of the local pointer variable, and the allocation remains unless the program frees it.
  • “Heap is always slower” or “the stack has a fixed size.” Neither claim is established by the language standard. Speed and limits depend on the implementation.
  • “malloc zeroes memory.” It returns uninitialized storage. Initialize the values yourself before reading them.

Further reading

For a broader introduction to the C language that covers these topics in context, Pearson’s listing for The C Programming Language, Second Edition, by Brian W. Kernighan and Dennis M. Ritchie (paperback, ISBN 9780131103627) describes the book as an introduction to C. It is a general language book rather than a guide to memory management, so treat it as supplementary reading. Edition and availability details may change.

The Bottom Line

Think in terms of lifetimes, not locations. Automatic objects end when their block exits, so never return a pointer to one. Allocated objects last until you free or reallocate them, so check every malloc result and release each allocation exactly once. Speed and capacity comparisons depend on the implementation and should be measured on your own target.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.