Fundamentals 15 min read

Unlock C Memory Layout: From Stack to Heap Explained with Real Code

This article demystifies C's memory layout by comparing it to a house, detailing each segment—from the stack and heap to global variables and the code section—while providing clear examples, common pitfalls, debugging tips, and interactive challenges to solidify understanding.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Unlock C Memory Layout: From Stack to Heap Explained with Real Code

Memory Layout Overview

The process address space is divided into distinct regions, each serving a specific purpose. The diagram below shows the typical layout from high to low addresses:

高地址  +------------------+
      |    环境变量区    | ← 环境变量(房间的空气)
      +------------------+
      |    命令行参数区  | ← 命令行参数(入户门)
      +------------------+
      |      栈区       | ← 函数调用,局部变量
      +------------------+
      |      ↓↓↓       | ← 栈向下增长
      +------------------+
      |      自由       | ← 未使用的内存空间
      +------------------+
      |      ↑↑↑       | ← 堆向上增长
      +------------------+
      |      堆区       | ← 动态分配内存
      +------------------+
      |   未初始化数据段 | ← 未初始化的全局变量 (BSS)
      +------------------+
      |   已初始化数据段 | ← 已初始化的全局变量 (Data)
      +------------------+
低地址  |      代码段       | ← 程序指令代码
      +------------------+

1. Stack (栈区)

The stack grows from high addresses toward low addresses. It stores local variables, function parameters, and return addresses. Allocation and deallocation are automatic (LIFO), making it fast but limited in size (typically a few megabytes).

void 做个菜() {
    int 西红柿 = 2; // 栈上局部变量
    int 鸡蛋 = 3;   // 也在栈上
}

int main() {
    做个菜();
    return 0; // 西红柿和鸡蛋在函数返回时自动清理
}

2. Heap (堆区)

The heap grows from low addresses toward high addresses. Memory is obtained with malloc (or calloc) and must be released with free. It provides large, flexible storage but is slower due to bookkeeping.

#include <stdlib.h>
int main() {
    int *动态数组 = (int*)malloc(10 * sizeof(int));
    if (动态数组 != NULL) {
        动态数组[0] = 42; // 使用堆内存
        free(动态数组);    // 记得释放,防止泄漏
    }
    return 0;
}

3. Global / Static Area

Global and static objects are placed in two segments:

Data segment (已初始化数据段) : variables with explicit initial values.

BSS segment (未初始化数据段) : zero‑initialized globals.

Both segments have static lifetime (exist for the entire program) and are allocated at compile time.

#include <stdio.h>
int 已初始化 = 100;   // Data段
int 未初始化;           // BSS段,自动为0
int main() {
    static int 静态局部 = 50; // 仍在 Data段,但作用域在函数内
    printf("未初始化的值是: %d
", 未初始化);
    return 0;
}

4. Code Segment

The code segment stores the executable instructions. It is typically marked read‑only to prevent accidental modification.

5. Command‑Line Arguments and Environment Variables

Command‑line arguments are passed to main via int argc, char *argv[]. The argv pointers reside on the stack, while the actual strings are placed in a special area set up by the operating system.

int main(int argc, char *argv[]) {
    printf("程序名: %s
", argv[0]);
    if (argc < 2) {
        printf("使用方法: %s 参数1 [参数2]
", argv[0]);
        return 1;
    }
    return 0;
}

Environment variables are stored in a region above the stack, created by the OS at program start.

#include <stdlib.h>
int main() {
    char *owner = getenv("USERNAME");
    if (owner) printf("欢迎回家,%s!
", owner);
    putenv("MOOD=开心");
    return 0;
}

Practical Memory Allocation Example

#include <stdio.h>
#include <stdlib.h>
int 炉灶 = 1;          // 已初始化数据段
int 水槽;               // BSS段,自动为0

void 炒菜(int 食材) {
    int 热油 = 100;
    int 调料 = 5;
    printf("用%d号炉灶炒一道菜,放了%d份调料
", 炉灶, 调料);
}

int main() {
    int 菜单计划 = 10;
    int *采购清单 = (int*)malloc(菜单计划 * sizeof(int));
    if (采购清单 != NULL) {
        采购清单[0] = 2; // 西红柿
        采购清单[1] = 3; // 鸡蛋
        炒菜(采购清单[0]);
        free(采购清单);
    }
    return 0;
}

Common Issues & Solutions

Stack Overflow

Occurs when recursion is too deep or large local arrays exhaust the stack.

void 堆满工作台() {
    char 大数组[1000000]; // 大局部数组占用大量栈空间
    堆满工作台();        // 无限递归导致栈溢出
}

Provide a clear termination condition for recursion.

Replace huge local arrays with heap allocations.

If necessary, increase stack size via compiler/linker options.

Memory Leak

void 储物间不清理() {
    int *物品 = (int*)malloc(100 * sizeof(int));
    // 使用物品...
    // 忘记 free(物品)!导致泄漏
}

Always pair each malloc / calloc with a matching free.

Run tools such as Valgrind to detect leaks.

Adopt the “who allocates, who frees” rule.

Dangling Pointer

int *制造悬空指针() {
    int 本地变量 = 10; // 栈上变量
    return &本地变量;   // 返回已失效的地址
}

Never return the address of a local (stack) variable.

After free, set the pointer to NULL.

Prefer heap allocation with explicit ownership.

Memory Debugging Techniques

1. Print Addresses

printf("变量地址: %p, 值: %d
", (void*)&变量, 变量);

2. Use Memory Checkers (Valgrind, Dr.Memory)

# 编译时加入调试信息
gcc -g 程序.c -o 程序
# 用 Valgrind 运行
valgrind --leak-check=full ./程序

3. Enable Compiler Warnings

gcc -Wall -Wextra -Werror 程序.c -o 程序

4. Assertions

#include <assert.h>
void 使用断言() {
    int *指针 = (int*)malloc(sizeof(int));
    assert(指针 != NULL);
    *指针 = 42;
    free(指针);
}

5. Debugger (gdb) Tips

Set breakpoints to observe stack changes.

Print addresses and sizes before/after malloc / free.

Use gdb backtrace to locate segmentation faults.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Cmemory layoutprogramming fundamentals
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.