首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >堆与栈的的关键区别

堆与栈的的关键区别

原创
作者头像
用户5527489
发布2025-10-04 20:02:07
发布2025-10-04 20:02:07
930
举报

一 在栈中申请空间清晰展示  int a=7  和  int b=8  的地址关系与内存字节排列(对应小端存储):

#include <stdio.h>

int main() {

代码语言:txt
复制
// 定义两个int变量
代码语言:txt
复制
int a = 7;
代码语言:txt
复制
int b = 8;
代码语言:txt
复制
// 1. 打印a和b的地址(%p为地址格式化符)
代码语言:txt
复制
printf("变量a的地址:&a = %p\n", &a);
代码语言:txt
复制
printf("变量b的地址:&b = %p\n", &b);
代码语言:txt
复制
printf("地址关系:&a %s &b\n\n", (&a > &b) ? ">" : "<"); // 验证地址大小
代码语言:txt
复制
// 2. 打印a的内存字节排列(将int\*转为char\*,按字节访问)
代码语言:txt
复制
printf("变量a = 7(十六进制:0x00000007)的内存字节排列(低地址→高地址):\n");
代码语言:txt
复制
unsigned char \*p\_a = (unsigned char \*)&a; // 用unsigned char\*逐个读取字节
代码语言:txt
复制
for (int i = 0; i < sizeof(int); i++) {
代码语言:txt
复制
    printf("地址 %p:0x%02X\n", p\_a + i, \*(p\_a + i));
代码语言:txt
复制
}
代码语言:txt
复制
// 3. 打印b的内存字节排列
代码语言:txt
复制
printf("\n变量b = 8(十六进制:0x00000008)的内存字节排列(低地址→高地址):\n");
代码语言:txt
复制
unsigned char \*p\_b = (unsigned char \*)&b;
代码语言:txt
复制
for (int i = 0; i < sizeof(int); i++) {
代码语言:txt
复制
    printf("地址 %p:0x%02X\n", p\_b + i, \*(p\_b + i));
代码语言:txt
复制
}
代码语言:txt
复制
return 0;

}

运行结果说明(以 x86 小端环境为例)

假设运行后输出如下(地址值因系统而异,但规律固定):

plaintext

变量a的地址:&a = 0061FEAC

变量b的地址:&b = 0061FEA8

地址关系:&a > &b

变量a = 7(十六进制:0x00000007)的内存字节排列(低地址→高地址):

地址 0061FEAC:0x07 // 低地址存低位字节(0x07)

地址 0061FEAD:0x00

地址 0061FEAE:0x00

地址 0061FEAF:0x00 // 高地址存高位字节(0x00)

变量b = 8(十六进制:0x00000008)的内存字节排列(低地址→高地址):

地址 0061FEA8:0x08 // 低地址存低位字节(0x08)

地址 0061FEA9:0x00

地址 0061FEAA:0x00

地址 0061FEAB:0x00 // 高地址存高位字节(0x00)

核心结论(与之前逻辑一致)

地址关系: &a > &b (先定义的  a  地址更高,符合栈“高地址→低地址生长”规则);

内存排列:小端存储下, int  的低位字节存在低地址(如  a=7  的  0x07  在最左侧低地址, 0x00  依次向高地址排列)

以下用 C 语言代码演示堆中申请  int a=7  和  int b=8 ,并通过输出展示它们的地址关系与内存字节排列(基于 x86 小端架构,堆与栈的地址生长方向完全相反):

二 在堆申请的核心代码(用  malloc  分配堆内存)

#include <stdio.h>

#include <stdlib.h> // 包含 malloc/free 函数

int main() {

代码语言:txt
复制
// 1. 在堆中申请两个 int 大小的空间(每个 int 4 字节)
代码语言:txt
复制
int \*a = (int \*)malloc(sizeof(int)); // 堆地址1:给 a 分配空间
代码语言:txt
复制
int \*b = (int \*)malloc(sizeof(int)); // 堆地址2:给 b 分配空间
代码语言:txt
复制
if (a == NULL || b == NULL) { // 检查堆申请是否成功(堆内存可能不足)
代码语言:txt
复制
    printf("堆内存申请失败!\n");
代码语言:txt
复制
    return 1;
代码语言:txt
复制
}
代码语言:txt
复制
// 2. 给堆中的 a、b 赋值
代码语言:txt
复制
\*a = 7;
代码语言:txt
复制
\*b = 8;
代码语言:txt
复制
// 3. 打印 a、b 的堆地址(%p 输出指针地址,即堆中变量的地址)
代码语言:txt
复制
printf("堆中 a 的地址:&a = %p\n", a);
代码语言:txt
复制
printf("堆中 b 的地址:&b = %p\n", b);
代码语言:txt
复制
printf("地址关系:a 的地址 %s b 的地址\n\n", (a > b) ? ">" : "<");
代码语言:txt
复制
// 4. 打印 a 的内存字节排列(按低地址→高地址顺序)
代码语言:txt
复制
printf("a = 7(十六进制:0x00000007)的堆内存字节(低→高):\n");
代码语言:txt
复制
unsigned char \*p\_a = (unsigned char \*)a; // 转为 char\* 逐个访问字节
代码语言:txt
复制
for (int i = 0; i < sizeof(int); i++) {
代码语言:txt
复制
    printf("地址 %p:0x%02X\n", p\_a + i, \*(p\_a + i));
代码语言:txt
复制
}
代码语言:txt
复制
// 5. 打印 b 的内存字节排列
代码语言:txt
复制
printf("\nb = 8(十六进制:0x00000008)的堆内存字节(低→高):\n");
代码语言:txt
复制
unsigned char \*p\_b = (unsigned char \*)b;
代码语言:txt
复制
for (int i = 0; i < sizeof(int); i++) {
代码语言:txt
复制
    printf("地址 %p:0x%02X\n", p\_b + i, \*(p\_b + i));
代码语言:txt
复制
}
代码语言:txt
复制
// 6. 释放堆内存(堆不会自动回收,必须手动 free,否则内存泄漏)
代码语言:txt
复制
free(a);
代码语言:txt
复制
free(b);
代码语言:txt
复制
a = NULL; // 避免野指针
代码语言:txt
复制
b = NULL;
代码语言:txt
复制
return 0;

}

二、运行结果(x86 小端环境,关键规律固定)

plaintext

堆中 a 的地址:&a = 00602010

堆中 b 的地址:&b = 00602014

地址关系:a 的地址 < b 的地址

a = 7(十六进制:0x00000007)的堆内存字节(低→高):

地址 00602010:0x07 // 低地址存低位字节 0x07

地址 00602011:0x00

地址 00602012:0x00

地址 00602013:0x00 // 高地址存高位字节 0x00

b = 8(十六进制:0x00000008)的堆内存字节(低→高):

地址 00602014:0x08 // 低地址存低位字节 0x08

地址 00602015:0x00

地址 00602016:0x00

地址 00602017:0x00 // 高地址存高位字节 0x00

三、核心结论(堆与栈的关键区别)

  1. 地址关系:堆是“低地址→高地址生长”(与栈完全相反)
  • 栈中:先定义的变量地址更高( &a > &b );
  • 堆中:先申请的变量地址更低( &a < &b )——因为堆从内存低地址向高地址扩展,先  malloc  的  a  占低地址,后  malloc  的  b  占更高地址(结果中  a=0x00602010 , b=0x00602014 ,差 4 字节,正好是一个 int 的大小)。
  1. 内存字节排列:堆与栈一致,遵循“小端存储”

无论在堆还是栈, int  类型的多字节数据都按“低字节存低地址、高字节存高地址”排列:

  •  a=7 (0x00000007):低地址存  0x07 ,高地址存  0x00 ;
  •  b=8 (0x00000008):低地址存  0x08 ,高地址存  0x00 ——这是 x86 架构的硬件规则,与内存区域(堆/栈)无关。
  1. 额外注意:堆需要手动申请/释放
  • 栈:局部变量由编译器自动分配/回收;
  • 堆:必须用  malloc  申请、 free  释放,否则会导致“内存泄漏”(堆内存被占用但无法回收)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档