首页 > 系统相关 >c++中内存分类

c++中内存分类

时间:2023-01-20 17:55:21浏览次数:54  
标签:初始化 存储 定义 静态 作用域 分类 c++ int 内存

局部变量,存储位置:栈,存储时间:变量所在程序运行时间

全局变量,存储位置:静态存储区,存储时间:程序运行时间

static 静态变量,存储位置:静态数据区,存储时间:第一次初始化到程序运行结束

new 手动分配,存储位置:堆区,存储时间:从new到delete

c++存储空间共分为5个:

静态存储区:程序编译的时候就已经分配好,用于存放全局变量,常量,局部静态变量,全局静态变量

全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

在 C++ 中 static 的内部实现机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。只能在main函数之前或者类的定义中进行定义,因为要实际的分配空间,所以不能在类的声明中定义

1、全局静态变量:
定义:.在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。
说明:
1)内存中的位置:静态存储区(静态存储区在整个程序运行期间都存在)
2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非它被显示初始化)
3)作用域:全局静态变量在声明它的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。
定义全局静态变量的好处:
1)不会被其他文件所访问,修改。
2)其他文件中可以使用相同名字的变量,不会发生冲突。

2、局部静态变量:
定义:在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。
说明:
1)内存中的位置:静态存储区
2)初始化:未经初始化的局部静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)
3)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。
注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区。但是局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对它进行访问。
当static用来修饰全局变量的时候,它就改变了全局变量的作用域(在声明它的文件之外是不可见的),但是没有改变它的存放位置,还是在静态存储区中。

 

局部静态变量和全局静态变量的作用域为当前文件或当前类变量,不可被其他文件调用,定义范围是函数外,可以在头文件中定义,但是不能在类的声明中定义。

全局变量的作用域为其定义位置开始,至文件结尾,也即只有文件作用域,extern可以扩展全局变量的作用域使其可以被其他的文件调用,定义范围是函数外,可以在头文件中定义

常量是固定值,一经定义无法进行修改,作用域为定义的函数或者文件或者类内,定义范围define为函数外,const为任意位置

test.cpp:

#include<iostream> #include"test1.hpp" using namespace std;   int num5 = 1;//定义全局变量,作用域为当前文件从这一行到下面所有,其他文件可使用extern调用 //static int num4 = 1;//定义全局静态变量,作用域为当前文件,其他文件不可使用extern进行调用 // static int num4;//如果没有初始化,会默认初始化为0 // int Fun(int num1) // { //   int num2=0; //   static int num3=3;//定义局部静态变量,只会初始化一次 //   num2=num2+1; //   num3=num3+1; //   return num1+num2+num3+num4; // } int main() {   int i,num;   num=2;   for(i=0;i<3;i++)   {     cout<<Fun(num)<<" "<<endl;   }   return 0; } test.hpp: #include<iostream> using namespace std; extern int num5; static int num4;//如果没有初始化,会默认初始化为0 #define NUM6 1//定义常量 const int  NUM7 = 1;//定义常量 int Fun(int num1) {   int num2=0;   static int num3=3;//定义局部静态变量,只会初始化一次   num2=num2+1;   num3=num3+1;   return num1+num2+num3+num4+num5+NUM6+NUM7; }   栈区:用于存储局部变量 函数执行结束的时候局部变量自动的释放,栈区效率很高,但是分配的内存容量有限   堆区:动态内存分配区 使用new来申请,使用delete来删除,生存期有程序员决定,但是要注意删除,以及删除了之后要将指针指向NULL,防止产生野指针   文字常量区:用于存储常量字符串   程序代码区:用于存放函数的二进制代码  

堆与栈的区别:
主要有6点区别:

1、管理方式不同:
对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

2、空间大小不同:
一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改: 打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。 注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。

3、产生碎片不同:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在它弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。

4、生长方向不同:
对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

5、分配方式不同:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,无需我们手工实现。

6、分配效率不同:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。 虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。

 

参考(85条消息) C++内存空间:静态存储区、栈、堆、文字常量区、程序代码区_algsup的博客-CSDN博客_c++静态存储区

标签:初始化,存储,定义,静态,作用域,分类,c++,int,内存
From: https://www.cnblogs.com/uestc-du/p/17062906.html

相关文章

  • C++基础
    I/Ocout保留有效数字问题C++中cout默认保留六位有效数字,并且进行四舍五入修改保留数的方法cout.precision(2);//用这个来改变默认保留几位小数cout<<"保留两位有效:......
  • python/c++ 混合编程
    官方简介pybind11isalightweightheader-onlylibrarythatexposesC++typesinPythonandviceversa,mainlytocreatePythonbindingsofexistingC++code.......
  • C++获取含有中文字符的string长度
    :前言造车轮的时候要用到中文字符串的长度辨别,发现char的识别不准,进行了一番研究。>开始研究在Windows下,中文字符在C++中的内存占用为2字节,此时采用字符串长度获取函......
  • 硬件分类
    一传感器壹模拟信号(有不同档位)1.旋钮电位器GND接地VCC接电源3.3VOUT输出引脚2.摇杆电位器(反馈x,y坐标)GND接地+5V接电源5VVRXx坐标输出VRYy坐标输出......
  • Linux的mmap文件内存映射机制
    在讲述文件映射的概念时,不可避免的要牵涉到虚存(SVR4的VM).实际上,文件映射是虚存的中心概念,文件映射一方面给用户提供了一组措施,好似用户将文件映射到自己地址空......
  • Windows下udp广播【C++】
     最近学习了下Windows下的Socket使用,在这里记录一下。 前置准备 在使用api前,需要做一些必要的准备。头文件包含  //包括Winsock2头文件使用WinsockAPI,......
  • C++ 类中定义成员类型名
    C++可以在类中给某个类型定义一个只属于该类的成员类型名,使得可以通过类名::成员类型名来访问该类型这在我使用C#过程中是从来没有遇到过的,最开始遇到的时候真的很懵逼如......
  • C++缺省源
    C++竞赛使用缺省源(初稿)点击查看代码/* Author:Sean_xzx RightOutput!&Accepted!本题核心:1.本题步骤:1.*/#include<bits/stdc++.h>#definefz(i,a,b)fo......
  • PyTorch图像分类全流程实战--预训练模型预测图像分类02
    主要内容今天的任务是学习预训练模型的使用,模型是Resnet18,使用的torchvision包由流行的数据集、模型体系结构和通用的计算机视觉图像转换组成。简单地说就是常用数据集+常......
  • 一个C#将字节流通过管道传输到C++的问题
    提问: 提问一个C#将字节流通过管道传输到C++的问题现有一个字节流数据需要通过管道传输到C++,目前使用的方法是转成string通过WriteLine写入管道中,在C++中通过ReadFile读取......