C/C++变量内存分布详解与测试

沈知远
沈知远
发布时间:2026-10-14 | 3人浏览过
原创

C/C++中变量的内存分布在计算机基础和笔试中经常出现。为了准确理解各类型变量(如全局、静态、局部、堆)的地址分配规律,我们可以通过编写测试代码观察运行结果,从而掌握其背后的内存管理机制。

单函数环境下的内存分布

首先,我们在主函数中定义不同类型的变量,并打印它们的地址和值。以下测试程序包含全局变量、静态变量、局部变量(栈)、堆内存申请以及字符串常量。

  1. 准备条件:引入 <stdio.h> 和 <malloc.h> 头文件。
  2. 定义全局变量:
    • 已初始化: int g_i = 100;, int g_j = 200;
    • 未初始化: int g_k, g_h;
  3. 定义静态变量(主函数内):
    • 已初始化: static int s_i = 5;, static int s_j = 10;
    • 未初始化: static int s_k;, static int s_h;
  4. 定义局部变量(栈):
    • 已初始化: int i = 5;, int j = 10;, int k = 20;
    • 未初始化: int f, h;
  5. 动态内存(堆):使用 malloc 分配内存,指针为 p。
  6. 字符串常量:
    • char *pstr1 = "MoreWindows...";
    • char *pstr2 = "MoreWindows...";
    • char *pstr3 = "Hello";
#include <stdio.h>
#include <malloc.h>

int g_i = 100;
int g_j = 200;
int g_k, g_h;

int main()
{
    const int MAXN = 100;
    int *p = (int*)malloc(MAXN * sizeof(int));
    static int s_i = 5;
    static int s_j = 10;
    static int s_k;
    static int s_h;
    
    int i = 5;
    int j = 10;
    int k = 20;
    int f, h;
    
    char *pstr1 = "MoreWindows123456789";
    char *pstr2 = "MoreWindows123456789";
    char *pstr3 = "Hello";

    printf("堆中数据地址:0x%08x\n", p);

    putchar('\n');
    printf("栈中数据地址(有初值):0x%08x = %d\n", &i, i);
    printf("栈中数据地址(有初值):0x%08x = %d\n", &j, j);
    printf("栈中数据地址(有初值):0x%08x = %d\n", &k, k);
    printf("栈中数据地址(无初值):0x%08x = %d\n", &f, f);
    printf("栈中数据地址(无初值):0x%08x = %d\n", &h, h);

    putchar('\n');
    printf("静态数据地址(有初值):0x%08x = %d\n", &s_i, s_i);
    printf("静态数据地址(有初值):0x%08x = %d\n", &s_j, s_j);
    printf("静态数据地址(无初值):0x%08x = %d\n", &s_k, s_k);
    printf("静态数据地址(无初值):0x%08x = %d\n", &s_h, s_h);

    putchar('\n');
    printf("全局数据地址(有初值):0x%08x = %d\n", &g_i, g_i);
    printf("全局数据地址(有初值):0x%08x = %d\n", &g_j, g_j);
    printf("全局数据地址(无初值):0x%08x = %d\n", &g_k, g_k);
    printf("全局数据地址(无初值):0x%08x = %d\n", &g_h, g_h);

    putchar('\n');
    printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr1, pstr1, pstr1);
    printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr2, pstr2, pstr2);
    printf("字符串常量数据地址:0x%08x 指向 0x%08x 内容为-%s\n", &pstr3, pstr3, pstr3);
    
    free(p);
    return 0;
}

在Release版本环境下运行上述程序,观察输出结果的内存地址分布情况。

内存分布规律总结

通过运行结果分析,可以得出以下关于C/C++变量内存分布的核心结论:

  1. 内存区域顺序:在典型的进程内存布局中,从低地址到高地址的分布大致为:堆 - 栈 - 代码区 - 全局/静态区 - 常量区(注:不同操作系统和编译器可能略有差异,但总体趋势一致)。
  2. 同区域分配规则:同一内存区域内的变量,通常按照源代码中声明的顺序由低地址向高地址分配空间。
  3. 未初始化变量行为:
    • 全局变量和静态变量:如果不赋值,编译器会将它们放入未初始化的数据段(BSS),其默认值为 0。
    • 栈中的局部变量:如果不赋值,其内容是随机的(垃圾数据),不会自动清零。
  4. 编译器的优化处理:全局变量和静态变量在初始化方面被视作同类。已初始化的全局和静态变量会被分配到一起,未初始化的则分配到另一个区域(即.data段和.bss段)。

多函数调用时的内存行为

为了进一步验证栈的生长方向和静态变量的跨函数表现,我们增加一个子函数调用场景。子函数内部也定义了参数、局部变量和静态变量。

#include <stdio.h>

void fun(int i)
{
    int j = i;
    static int s_i = 100;
    static int s_j;

    printf("子函数的参数:           0x%p = %d\n", &i, i);
    printf("子函数 栈中数据地址:     0x%p = %d\n", &j, j);
    printf("子函数 静态数据地址(有初值): 0x%p = %d\n", &s_i, s_i);
    printf("子函数 静态数据地址(无初值): 0x%p = %d\n", &s_j, s_j);
}

int main()
{
    int i = 5;
    static int s_i = 100;
    static int s_j;

    printf("主函数 栈中数据地址:      0x%p = %d\n", &i, i);
    printf("主函数 静态数据地址(有初值): 0x%p = %d\n", &s_i, s_i);
    printf("主函数 静态数据地址(无初值): 0x%p = %d\n", &s_j, s_j);
    
    putchar('\n');

    fun(i);
    return 0;
}

观察运行结果:

结合两次测试的结果,可以确认以下关键点:

  1. 栈的生长方向:主函数中栈上的变量地址高于子函数中参数及局部变量的地址。这证明了栈是从高地址向低地址扩展生长的。
  2. 静态变量的生命周期:主函数和子函数中的静态变量地址是相邻或独立的,说明静态变量存储在独立的全局静态存储区,不因函数调用结束而销毁,且不同作用域的静态变量遵循相同的合并规则(按初始化状态分组)。
  3. 变量作用域:尽管变量名可能在多个作用域重复(如 s_i),但它们是不同的内存实体,仅在各自的作用域内可见。

以上就是C/C++变量在内存中的分布位置的详细内容,更多关于C/C++内存管理和底层原理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表