C++并不难—之内存分配

2023-11-14

很多人都觉得学习C++是特别困难的事情。C++学习是比较复杂的:它的内存分配、指针、以及面向对象思想的实现等等,确实需要一定的技术积累。我们将以专题的形式,为大家逐一剖析c++的技术重点和难点。

    本专题讨论的就是内存分配。学习c++如果不了解内存分配是一件非常可悲的事情。而且,可以这样讲,一个C++程序员无法掌握内存、无法了解内存,是不能够成为一个合格的C++程序员的。

    一、内存基本构成
    可编程内存在基本上分为这样的几大部分:静态存储区、堆区和栈区。他们的功能不同,对他们使用方式也就不同。
    静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
    栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
    堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。

    二、三者之间的区别
    我们通过代码段来看看对这样的三部分内存需要怎样的操作和不同,以及应该注意怎样的地方。
    例一:静态存储区与栈区

char* p = “Hello World1”;

char a[] = “Hello World2”;

p[2] = ‘A’;

a[2] = ‘A’;

 

char* p1 = “Hello World1;”


    这个程序是有错误的,错误发生在p[2] = ‘A’这行代码处,为什么呢,是变量p和变量数组a都存在于栈区的(任何临时变量都是处于栈区的,包括在main()函数中定义的变量)。但是,数据 “Hello World1”和数据“Hello World2”是存储于不同的区域的。

    因为数据“Hello World2”存在于数组中,所以,此数据存储于栈区,对它修改是没有任何问题的。因为指针变量p仅仅能够存储某个存储空间的地址,数据“Hello World1”为字符串常量,所以存储在静态存储区。虽然通过p[2]可以访问到静态存储区中的第三个数据单元,即字符‘l’所在的存储的单元。但是因为数据“Hello World1”为字符串常量,不可以改变,所以在程序运行时,会报告内存错误。并且,如果此时对p和p1输出的时候会发现p和p1里面保存的地址是完全相同的。换句话说,在数据区只保留一份相同的数据(见图1-1)。

    例二:栈区与堆区

char*  f1()

{

   char* p = NULL;

   char a;

   p = &a;

   return p;

}

char* f2()

{

   char* p = NULL:

   p =(char*)  new  char[4];

   return p;

}


    这两个函数都是将某个存储空间的地址返回,二者有何区别呢?f1()函数虽然返回的是一个存储空间,但是此空间为临时空间。也就是说,此空间只有短暂的生命周期,它的生命周期在函数f1()调用结束时,也就失去了它的生命价值,即:此空间被释放掉。所以,当调用f1()函数时,如果程序中有下面的语句:

 

char* p ;

p = f1();

*p = ‘a’;


    此时,编译并不会报告错误,但是在程序运行时,会发生异常错误。因为,你对不应该操作的内存(即,已经释放掉的存储空间)进行了操作。但是,相比之下, f2()函数不会有任何问题。因为,new这个命令是在堆中申请存储空间,一旦申请成功,除非你将其delete或者程序终结,这块内存将一直存在。也可以这样理解,堆内存是共享单元,能够被多个函数共同访问。如果你需要有多个数据返回却苦无办法,堆内存将是一个很好的选择。但是一定要避免下面的事情发生:

 

void f()

{

   …

   char * p;

   p = (char*)new char[100];

   …

}


    这个程序做了一件很无意义并且会带来很大危害的事情。因为,虽然申请了堆内存,p保存了堆内存的首地址。但是,此变量是临时变量,当函数调用结束时p变量消失。也就是说,再也没有变量存储这块堆内存的首地址,我们将永远无法再使用那块堆内存了。但是,这块堆内存却一直标识被你所使用(因为没有到程序结束,你也没有将其delete,所以这块堆内存一直被标识拥有者是当前您的程序),进而其他进程或程序无法使用。我们将这种不道德的“流氓行为”(我们不用,却也不让别人使用)称为内存泄漏。这是我们C++程序员的大忌!!请大家一定要避免这件事情的发生。

    总之,对于堆区、栈区和静态存储区它们之间最大的不同在于,栈的生命周期很短暂。但是堆区和静态存储区的生命周期相当于与程序的生命同时存在(如果您不在程序运行中间将堆内存delete的话),我们将这种变量或数据成为全局变量或数据。但是,对于堆区的内存空间使用更加灵活,因为它允许你在不需要它的时候,随时将它释放掉,而静态存储区将一直存在于程序的整个生命周期中。
我们此专题仅仅是简要的分析了内存基本构成以及使用它们时需要注意的问题。对内存的分析和讨论将一直贯穿于我们以后所有的专题,这也就是为什么把它作为第一讲的原因。

 

我们都知道,c/c++程序的内存分配,有这样几个存储区。

全局/静态数据区:存储全局变量,和静态变量static声明的变量

常量存储区:存储常量,如char *s="abcde"; 或者 const int i =10;代码区:这个不说了。代码放的地儿

栈:临时变量,参数等,有大小限制,vc6/7: 1M

堆: 用户自己维护的空间,内存使用需要自己申请,自己释放。大小基本不限(4G)

example:

#include <iostream>
using namespace std;

int global = 100; //全局/静态区
const int N = 10; //常量区

int main()
{
static int a = 0; //全局/静态区

char arr[100]="test";//arr分配在栈上,"test"分配到常量区,还有一个副本在栈上


char *s = "abcde";//s分配在栈上,"abcde"分配在常量区
char*str = NULL; //str分配在栈上

str = new char[10];//str所指向的空间分配在堆上
delete []str;

return 0;
}

 

 -------------------------------------------
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++并不难—之内存分配 的相关文章

  • 当从后台工作程序发生事件时,XlCall.Excel(XlCall.xlcCalculateNow) 抛出 XlCallException

    我有一个 ExcelFunction 来排队一些计算 ExcelFunction public static void QueueCalcs takes ranges var calcRequests builds list of calc
  • 从 Invoke 方法获取 RETURN

    我正在尝试从另一个线程上的列表框项目中读取值 我尝试创建一种新方法来运行调用命令 我可以设法将命令发送到列表框 例如通过调用方法添加 但我似乎无法得到响应 我似乎无法获取该项目的值 我尝试了几种方法 一旦我将它从空变为字符串 事情就开始变得
  • Nullable 是不可能的,为什么不呢? [复制]

    这个问题在这里已经有答案了 如果这是一个愚蠢的问题 请原谅 我正在尝试更好地理解 Net 中的 Nullable 类型 从我从 Microsoft 源代码 使用 ReSharper 中注意到的内容 我了解到 Nullable 是一个结构 而
  • libtool 在 Ubuntu 13.04 上构建 thrift 0.9.1 时出错

    在 Ubuntu 13 04 上构建 thrift 0 9 1 支持 C C java C perl python 时出现此错误 configure 不带任何选项运行 make 不带任何选项运行 Making all in test mak
  • C# Outlook 从收件人获取 CompanyName 属性

    我目前正在使用 C 编写 Outlook 2010 AddIn 我想要的是从我从 AppointmentItem 中提取的 Recipient 对象中获取 CompanyName 属性 因此 有了 AppointmentItem 的收件人
  • 具有多个谓词的 C++11 算法

    功能如std find if来自algorithmheader 确实很有用 但对我来说 一个严重的限制是我只能为每次调用使用 1 个谓词count if 例如给定一个像这样的容器std vector我想同时应用相同的迭代find if 多个
  • 在 Mac OS X 上安装 libxml2 时出现问题

    我正在尝试在我的 Mac 操作系统 10 6 4 上安装 libxml2 我实际上正在尝试在 Python 中运行 Scrapy 脚本 这需要我安装 Twisted Zope 现在还需要安装 libxml2 我已经下载了最新版本 2 7 7
  • 从时间列表中查找最接近的时间

    所以 这是场景 我有一个带有创建时间的文件 我想从该文件的创建时间最接近或相等的时间列表中选择一个时间 完成此操作的最佳方法是什么 var closestTime listOfTimes OrderBy t gt Math Abs t fi
  • 判断串口是普通COM还是SPP

    我正在寻找一种方法来确定 COM 是标准 COM 还是 SPP COM 也称为 COM 设备的电缆替换蓝牙适配器 我有一个可以在 USB COM gt USB 和蓝牙下工作的设备 并且蓝牙接口可以与 SPP 一起工作 我目前正在使用Syst
  • 如何设置消息队列的所有者?

    System Messaging MessageQueue 类不提供设置队列所有权的方法 如何以编程方式设置 MSMQ 消息队列的所有者 简短的答案是 p invoke 对 windows api 函数的调用MQSetQueueSecuri
  • 如何对STL向量进行排序?

    我想排序一个vector vector
  • 选择 asp.net CheckBoxList 中的所有项目

    ASP NET 和 C 我想要一个带有 全选 项目的复选框列表 当这个特定项目是 已选择 所有其他都将被选择 也 当选择被删除时 这个项目 也将来自所有人 其他物品 选中 取消选中 任何其他项目只会有一个 对特定项目的影响 无论选择状态如何
  • 在 mvc4 中创建通用 mvc 视图

    我以前也提过类似的问题 没有得到答案 如何创建一个通用的 mvc4 视图 该视图可以显示传递给它的模型列表或单个模型 模型可以是个人 组织或团体 无论传递给它的是什么 如果您正在寻找类似的东西 model MyViewModel
  • 用数组或向量实现多维数组

    我想使用单个数组或向量实现多维数组 可以像通常的多维数组一样访问它 例如 a 1 2 3 我陷入困境的是如何实施 操作员 如果数组的维数为 1 则 a 1 应该返回位于索引 1 处的元素 但是如果维数大于一怎么办 对于嵌套向量 例如 3 维
  • 时间:2019-03-17 标签:c#TimerStopConfusion

    我想通过单击按钮时更改文本颜色来将文本框文本设置为 闪烁 我可以让文本按照我想要的方式闪烁 但我希望它在闪烁几次后停止 我不知道如何在计时器触发几次后让它停止 这是我的代码 public Form1 InitializeComponent
  • 使用 boost 异步发送和接收自定义数据包?

    我正在尝试使用 boost 异步发送和接收自定义数据包 根据我当前的实现 我有一些问题 tcpclient cpp include tcpclient h include
  • 初始化列表在 VC10 中不起作用

    我在 VC 2010 中编写了这个程序 class class1 public class1 initializer list
  • 使用 IdentityDbContext 和 Code First 自动迁移表位置和架构的实体框架?

    我正在尝试使用 IdentityDbContext 类设置自动迁移更新 并将更改传播到整个数据库的实际 DbContext 在进入代码之前 在使用自动迁移实现 IdentityDbContext 时 我收到此错误 影响迁移历史系统表位置的自
  • 对多个对象使用事件处理程序

    我有 20 件物品List
  • 运行 xunit 测试时无法将输出打印到控制台窗口

    public class test2InAnotherProject private readonly ITestOutputHelper output public test2InAnotherProject ITestOutputHel

随机推荐

  • Go设置国内源

    Go设置国内源 如果你需要Beego这个框架 正常来说你需要安装Git之后go get不会报错 但由于网络问题 go get会非常慢 以至于没法使用 这个时候我们需要需要国内源来进行加速 首先需要我们开启Go的MODULL支持 SETX G
  • 从零开始的ESP8266探索(16)-扫描网络演示

    文章目录 目的 使用演示 同步扫描 异步扫描 总结 目的 ESP8266可以通过扫描获取周围环境中的WiFi热点 所以我们也可以先扫描一下再决定连接到某个网络上 这也是一种常见的应用场景 使用演示 同步扫描 使用下面代码进行同步扫描 同步扫
  • 59. 螺旋打印情况

    i 代表一圈 j 从用来上下左右移动 主要是控制 i 与j 的参数关系就ok了 另一个是注意如何初始化 从左上角到右上角 while j
  • CScrollView嵌入对话框中无法响应WM_MOUSE WHEEL 消息

    1 问题描述 当使用CScrollView来显示图像时 往往需要将它嵌入到对话框中 当嵌入对话框之后 显示图像 使用放大镜查看图像时 发现使用WM MOUSE WHEEL消息来放大和缩小放大镜 结果消息未响应 2 分析原因 跟着调试发现 C
  • 基于LLaMA-2进行微调的FreeWilly2开源语言模型

    FreeWilly2是由Stability AI基于Llama2 70B所微调后发布的大语言模型 该模型的部分推理能力甚至已经超越了openAI的GPT 3 5 截止至发稿前 该模型在HuggingFace的开源语言模型排行榜中位列榜首 大
  • FPGA的虚拟时钟如何使用?

    以下文章来源于傅里叶的猫 作者张大侠 但文中对虚拟时钟的应用介绍的还不够详细 因此这里我们再对虚拟时钟做一个更加细致的介绍 首先 虚拟时钟用于什么地方 虚拟时钟通常用于设定输入和输出的延时 即set input delay和set outp
  • python 读取dll、exe文件版本终极方案

    网上找到的大都是调用win32api 但是这个api很多dll识别失败了 推荐使用wind32com 它兼容性比较强 1 使用win32api import os import win32api def getFileVersion fil
  • AlmaLinux构建LNMP

    环境 虚拟机 AlmaLinux9 1 hostname localhost ip 192 168 123 228 查看系统 cat etc redhat release 确保软件包管理器是最新的 yum clean all yum upd
  • 已解决AttributeError: ‘list‘ object has no attribute ‘text‘

    已解决AttributeError list object has no attribute text 文章目录 报错问题 报错翻译 报错原因 解决方法 千人全栈VIP答疑群联系博主帮忙解决报错 报错问题 粉丝群里面的一个小伙伴遇到问题跑来
  • 时间序列预测误差_时间序列-误差指标

    时间序列预测误差 时间序列 误差指标 Time Series Error Metrics It is important for us to quantify the performance of a model to use it as
  • 2023年电工杯B题问题二三思路讲解+创新点

    问题二三解题思路 1 根据你们对数据的分析结果选取评价指标 从优先级 科学性 可操作性等方面论述其合理性 并构建评价指标体系 2 建立数学模型 评价人工智能对大学生学习的影响 给出明确 有说服力的结论 这两问 可以看作一个问题 即针对人工智
  • anguar一个空间多个项目实战

    一 前言 有时候我们在一条产品线上 会有多套前端代码 运行在不同平台或者有多个业务端 这些代码可复用性非常高 以至于可以从某套代码直接copy出来用于开发另一个业务端 于是某个小组件需要改动时却要跑起多个项目来修改 angular cli很
  • js的日志输出console.log 你真的会使用吗

    在JavaScript中 可以使用console对象在控制台中输出信息 以下是一些常用的console方法 log 输出一般信息 console log Hello World error 输出错误信息 console error An e
  • This custom view should extend androidx.appcompat.widget.AppCompatTextView instead

    报错信息 第一种 This custom view should extend androidx appcompat widget AppCompatTextView instead 这是新版 第二种 This custom view sh
  • 弹性云服务器(Elastic Cloud Server,ECS)

    弹性云服务器 Elastic Cloud Server ECS https support huaweicloud com ecs index html 弹性云服务器 Elastic Cloud Server 是一种可随时自动获取 计算能力
  • Revit2014: 板Slab在创建时候提示错误:“边界边缘线彼此相交。边界等高线不可扭曲。”

    在Revit 2014里面 调用NewSlab方法抛出一个奇怪的错误 Boundary edge lines intersect each other Boundary contour must not be distorted 中文是这样
  • restTemplate踩过的坑-spring clound

    现在公司项目基本都从臃肿的项目转换成微服务的方向转换 因此也从中使用了spring clound的一些组件 在此过程中就遇到了restTemplate的坑 起初 是直接注入RestTemplate 后来则不断的遇到错误日志无法请求 出现异常
  • FFmpeg 视频常用处理命令指定时间处理

    ffmpeg处理命令较多 但在指定时间处理的比较少 做个记录分享 合成文字命令 ffmpeg i old mp4 vf drawtext fontfile simhei ttf text aaaaa x 500 y 100 fontsize
  • js判断一个对象是否在一个对象数组中

    一 使用includes 方法 意为存在 存在返回true 不存在返回false 重点是要结合JSON stringify 序列化为字符串后再判断 var arr appName 小何 appId 1 appName 小王 appId 2
  • C++并不难—之内存分配

    很多人都觉得学习C 是特别困难的事情 C 学习是比较复杂的 它的内存分配 指针 以及面向对象思想的实现等等 确实需要一定的技术积累 我们将以专题的形式 为大家逐一剖析c 的技术重点和难点 本专题讨论的就是内存分配 学习c 如果不了解内存分配