温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++的代码区、全局区、栈区和堆区是什么

发布时间:2022-03-28 09:52:16 来源:亿速云 阅读:303 作者:iii 栏目:大数据

本篇内容主要讲解“C++的代码区、全局区、栈区和堆区是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++的代码区、全局区、栈区和堆区是什么”吧!

C++内存四区

C++ 在程序执行时,将内存大致分为代码区,全局区,栈区和堆区四个区域。不同的区域存储不同的数据,赋予不同的生命周期,能够更灵活地进行编程。

  1. 代码区:存放函数体的二进制代码,由操作系统管理创建,代码区时共享的,对于频繁被执行的程序,只需要存有一份代码即可;

  2. 全局区:存放全局变量和静态变量以及常量,在程序结束后由操作系统释放;

  3. 栈区:由编译其自动分配释放,存放函数的参数值以及局部变量等;

  4. 堆区:一般由程序员通过 new 开辟空间,进行分配和释放,若程序员不释放,则程序结束时由操作系统回收

下面通过一个例子对全局区,栈区,堆区的数据声明周期进行说明:

// 全局变量属于全局区,由操作系统管理释放
int g_a = 1;
int g_b = 2;
int main(void)
{
 cout << "g_a 的地址为:	"<< int(&g_a) << endl;
 cout << "g_b 的地址为:	" << int(&g_b) << endl;
 // 创建普通的局部变量,属于栈区
 int a = 10;
 int b = 20; 
 cout << "a 的地址为:	" << int(&a) << endl;
 cout << "b 的地址为:	" << int(&b) << endl;
 // 创建静态变量,属于全局区
 static int s_a = 40;
 static int s_b = 50;
 cout << "s_a 的地址为:	" << int(&s_a) << endl;
 cout << "s_b 的地址为:	" << int(&s_b) << endl;
 // 程序员自己创建变量,属于堆区
 int* d_a = new int(10);
 int* d_b = new int(20);
 cout << "d_a 的地址为:	" << int(d_a) << endl;
 cout << "d_b 的地址为:	" << int(d_b) << endl;
}

输出结果为:

g_a 的地址为:  5300224  g_b 的地址为:  5300228 
a 的地址为:    6421316  b 的地址为:    6421304
s_a 的地址为:  5300232  s_b 的地址为:  5300236
d_a 的地址为:  9547944  d_b 的地址为:  9547992

我们从中可以看到,g_a,g_b,s_a,s_b 都属于全局区,同理,a,b 都属于栈区,d_a,d_b 都属于堆区。由于栈区的数据在程序运行结束后会被编译器自动销毁,因此不要返回局部变量的地址,举例如下:

int* func()
{
 int a = 10; // 栈区数据,在程序执行完之后自动释放
 return &a; //虽然返回了a的地址,然而数据在func结束时已经被销毁
}

int main(void)
{
 int* a = func(); // 此时a表示在函数func在栈区开辟的地址,但是其中的数据已被销毁
 cout << "a 的地址为:	" << int(a) << "a 存放的数据为:	" << *a << endl;
 cout << "a 的地址为:	" << int(a) << "a 存放的数据为:	" << *a << endl;
}

输出结果为:

a 的地址为:    7601480a 存放的数据为: 10
a 的地址为:    7601480a 存放的数据为: 2084553696

由于编译器会对栈区的数据做一次保留,因此第一条的 cout 语句能够正常输出,然而第二次的输出才是内存地址 a 中的数据。

相反,堆区数据由程序员自己进行管理,在程序执行完之后并不会自动释放。当整个程序执行完毕之后会由操作系统释放。

int* func()
{
 int * a = new int(10); // 程序员使用new在堆区开辟空间,在程序执行完之后自动释放
 return a; //同样返回了a的地址,然而只要程序没有运行结束,除非程序员释放,否则会一直保留
}

int main(void)
{
 int* a = func(); // 此时a表示在函数func在堆区开辟的地址,编译器无法自动销毁
 cout << "a 的地址为:	" << int(a) << "a 存放的数据为:	" << *a << endl;
 cout << "a 的地址为:	" << int(a) << "a 存放的数据为:	" << *a << endl;
}

输出结果为:

a 的地址为:    23507016a 存放的数据为:        10
a 的地址为:    23507016a 存放的数据为:        10

附:内存四区的小结

1、栈区(stack):就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区。里面的变量通常是函数的返回地址、参数、局部变量、返回值等,从高地址向低地址增长。在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。其操作方式类似于数据结构中的栈。

2、堆区(heap): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,在程序运行过程中可以动态增加堆大小(移动break指针),从低地址向高地址增长。

        堆:是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free()可把内存交还。

        自由存储区:自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区和堆区就有区别了。

3、数据区:主要包括静态全局区和静态区,如果要站在汇编角度细分的话还可以分为很多小的区。

        全局区&静态区:全局变量和静态变量被分配到同一块内存中,在以前的 C 语言中,全局变量和静态变量又分为

    全局初始化区(DATA段) :存储程序中已初始化的全局变量和静态变量

    未初始化段(BSS段) :存储未初始化的全局变量和静态变量(局部+全局)。BSS段在DATA段的相邻的另一块区域。

              BBS段特点:在程序执行前BBS段自动清零,所以未初始化的全局变量和静态变量在程序执行前已经成为0。

  在 C++ 里面没有这个区分了,他们共同占用同一块内存区。

4、代码区:包括只读存储区和文本区,其中只读存储区存储字符串常量,就是常量区,文本区存储程序的机器代码。

那“内存四区”和“内存五区”有什么区别吗?

其实“内存四区”和“内存五区”指的东西都是完全一样的

内存五区为:栈区、堆区、全局区(静态区)、常亮区、代码区

内存四区为:栈区、堆区、数据区(全局区(静态区)、常亮区)、代码区

因此从上面可以看出,对于内存四区而言,其只是把全局区(静态区)和常亮区合并为一个数据区而已,其实内容都是完全一样的

到此,相信大家对“C++的代码区、全局区、栈区和堆区是什么”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

c++
AI