【C++入门到精通】C++入门 —— 内存管理(new函数的讲解)上

简介: 【C++入门到精通】C++入门 —— 内存管理(new函数的讲解)上

前言


       前面我们讲了C语言的基础知识,也了解了一些数据结构,并且讲了有关C++的命名空间的一些知识点以及关于C++的缺省参数、函数重载,引用 和 内联函数也认识了什么是类和对象。也相信大家都掌握的不错,接下来博主将会带领大家继续学习有关C和C++比较重要的知识点——内存管理。下面话不多说坐稳扶好咱们要开车了😍


一、C/C++内存分布


        C/C++的内存分布较为复杂,大概分为五个部分它们分别是:栈(Stack)、堆(Heap)、全局区/静态区(Global Area/Static Area)、常量区(Constant Area)、代码区(Code Area)下面我会分别介绍他们各自的属性。


1. 栈(Stack)


🍟栈是用来存储函数的局部变量、函数参数和函数调用的返回地址等信息的内存空间。

🍟栈空间由编译器自动管理,它的分配和释放是自动进行的,不需要程序员手动操作。

🍟每当一个函数被调用时,编译器会在栈上为该函数分配一块特定大小的空间,称为函数帧或活动记录(Activation Record)。

🍟栈是一种高效的存储方式,由于栈上的内存是连续分配的,因此访问速度较快。然而,栈的大小是有限的,过多的栈帧可能导致栈溢出的错误。


2. 堆(Heap)


🍁堆是用来动态分配内存的空间,通过使用malloc、free、new、delete等操作来分配和释放内存。

🍁堆的分配是手动进行的,程序员需要显式地分配和释放内存。

🍁堆是一种灵活的存储方式,允许动态调整分配的内存大小。

🍁堆上的内存分配通常是不连续的,因此访问速度稍慢于栈。

🍁如果使用不当,堆上的内存可能导致内存泄漏或内存碎片化等问题。


3. 全局区/静态区(Global Area/Static Area)


🍔全局区用来存储全局变量和静态变量。

🍔全局变量在程序开始执行时分配,在程序结束时被释放,因此它们的生命周期与整个程序的运行周期相同。

🍔静态变量有不同的存储位置和生命周期,具体取决于其作用域和存储类型(例如静态局部变量、静态全局变量)。

🍔全局区的内存空间在程序启动时由操作系统分配,并在程序退出时由操作系统释放。


4. 常量区(Constant Area)


🍪常量区用来存储常量数据,例如字符串字面量和其他常量。

🍪常量区的内存通常是只读的,因此程序不能对其进行修改。

🍪常量区的数据在程序运行期间保持不变。


5. 代码区(Code Area)


🥝代码区用来存储程序的机器指令,也称为可执行代码。

🥝代码区通常是只读的,存储程序的执行逻辑。

🥝代码区的内存空间在程序启动时被分配,并且在程序运行期间保持不变。


e900c8a9001b0b7d924543a38cd4e384_68b9dc8a8a814f08bdafd4190a9ea669.png


        🚨注意:具体的内存布局和分配方式可能因编译器、操作系统和硬件平台的不同而有所差异。此外,在多线程和多进程的情况下,还需要考虑线程栈、共享内存等特殊情况。


二、C语言中动态内存管理方式


1. malloc函数


  • malloc 函数用于动态地分配指定大小的内存空间。
  • 它接受一个参数,即需要分配的内存大小(以字节为单位),并返回所分配内存的起始地址。
int ptr = (int)malloc(sizeof(int));
  • malloc 函数在堆上找到足够大的连续内存空间进行分配,如果找不到足够大的连续空间,则返回 NULL
  • 分配的内存是未初始化的,即其中的数据是不确定的,需要手动初始化。
#include <stdio.h>
#include <stdlib.h>
int main() {
    int size;
    int* arr;
    printf("Enter the size of the array: ");
    scanf("%d", &size);
    // 使用malloc函数动态分配内存
    arr = (int*)malloc(size * sizeof(int));
    if (arr == NULL) {
        printf("Memory allocation failed!");
        return 1;
    }
    printf("Enter %d elements:\n", size);
    for (int i = 0; i < size; i++) {
        scanf("%d", &arr[i]);
    }
    printf("The elements you entered are: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    // 释放已分配的内存
    free(arr);
    return 0;
}


上面的程序实现了以下步骤:


  1. 用户输入数组的大小。
  2. 使用 malloc 函数动态分配足够大的内存空间来存储整数数组。
  3. 检查内存分配是否成功,如果分配失败,则输出错误信息并结束程序。
  4. 用户输入数组的元素。
  5. 打印用户输入的数组元素。
  6. 使用 free 函数释放分配的内存空间。


2. calloc函数


  • calloc 函数用于动态地分配指定数量和大小的内存空间,并将其初始化为0。
  • 它接受两个参数,第一个是需要分配的元素数量,第二个是每个元素的大小(以字节为单位)。
int ptr = (int)calloc(5, sizeof(int));
  • calloc 函数在堆上找到足够大的内存空间进行分配,并将所有字节初始化为0。
  • 分配的内存是初始化过的,不需要手动初始化。
#include <stdio.h>
#include <stdlib.h>
int main() {
    int size;
    int* arr;
    printf("Enter the size of the array: ");
    scanf("%d", &size);
    // 使用calloc函数动态分配内存,并将内存初始化为0
    arr = (int*)calloc(size, sizeof(int));
    if (arr == NULL) {
        printf("Memory allocation failed!");
        return 1;
    }
    printf("Enter %d elements:\n", size);
    for (int i = 0; i < size; i++) {
        scanf("%d", &arr[i]);
    }
    printf("The elements you entered are: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    // 释放已分配的内存
    free(arr);
    return 0;
}


       上面的代码功能跟上面 malloc 函数的示例表达的功能一样这里不做过多的解释,记得在完成使用动态分配的内存后,使用 free 函数释放已分配的内存,以免出现内存泄漏。


3. realloc函数


  • realloc 函数用于重新调整之前分配的内存空间的大小。
  • 它接受两个参数,第一个是之前分配内存的起始地址,第二个是需要调整的新大小(以字节为单位)
ptr = (int*)realloc(ptr, 10 * sizeof(int));
  • realloc 函数将尝试在原始内存空间上重新调整大小,如果成功,则返回调整后的内存地址;如果原始内存空间不够大或者其他错误,则返回 NULL
  • 若新大小大于原始大小,则新增的字节未初始化;若新大小小于原始大小,则超出新大小的部分将被丢弃。
#include <stdio.h>
#include <stdlib.h>
int main() {
    int size;
    int* arr;
    printf("Enter the size of the array: ");
    scanf("%d", &size);
    // 使用malloc函数动态分配内存
    arr = (int*)malloc(size * sizeof(int));
    if (arr == NULL) {
        printf("Memory allocation failed!");
        return 1;
    }
    printf("Enter %d elements:\n", size);
    for (int i = 0; i < size; i++) {
        scanf("%d", &arr[i]);
    }
    // 重新分配内存,将数组大小调整为10
    int newSize = 10;
    int* newArr = (int*)realloc(arr, newSize * sizeof(int));
    if (newArr == NULL) {
        printf("Memory reallocation failed!");
        free(arr);  // 释放之前分配的内存
        return 1;
    }
    // 更新指针arr的引用
    arr = newArr;
    // 打印数组元素
    printf("The elements you entered are: ");
    for (int i = 0; i < newSize; i++) {
        printf("%d ", arr[i]);
    }
    // 释放分配的内存
    free(arr);
    return 0;
}


        首先使用 malloc 函数动态分配内存,并在之后的 realloc 操作中进行了适当的错误处理。如果 realloc 函数返回 NULL ,表示内存调整失败,此时会输出错误信息并释放之前分配的内存。如果 realloc 函数成功,则将新分配的内存地址赋给 arr 指针,并继续使用调整后的内存。在最后,使用 free 函数释放分配的内存空间,并返回 0 表示程序正常结束


4. free函数


  • free 函数用于释放之前动态分配的内存空间。
  • 传入 free 函数的参数是之前分配的内存块的起始地址。
  • 调用free函数将释放所指定的内存空间,使其可供之后的malloc、calloc、realloc等函数重新使用。

       这些动态内存管理函数提供了灵活的内存分配和释放能力,可以根据需要动态调整内存的大小。然而,需要确保正确使用,避免内存泄漏和野指针等问题。建议在每次分配内存后检查分配是否成功,以及在适当的时候使用 free 函数释放不再需要的内存。


void Test ()
{
    int* p1 = (int*) malloc(sizeof(int));
    free(p1);
    int* p2 = (int*)calloc(4, sizeof (int));
    int* p3 = (int*)realloc(p2, sizeof(int)*10);
    // 这里需要free(p2)吗?  答:不用
    free(p3 );
}

       上面的代码中不需要 free(p2) 因为当调用realloc函数时,如果成功调整了内存大小,那么原始内存区域的内容将被复制到新分配的内存,并且原始的内存空间会被释放。因此,在这种情况下,不需要再手动调用 free(p2) 来释放原始的内存空间,因为realloc函数已经负责处理了。


目录
相关文章
|
4天前
|
SQL 数据库 Windows
YashanDB Windows客户端安装
本文介绍YashanDB客户端(Windows)的安装、使用及卸载步骤。首先,下载并解压软件包至本地路径,配置环境变量。接着,通过cmd窗口使用yasql命令连接数据库,执行SQL操作。最后,卸载时删除相关环境变量和客户端目录。更多功能请参考官方文档。
YashanDB Windows客户端安装
|
5天前
|
存储 虚拟化 Docker
Docker Desktop 4.38 安装与配置全流程指南(Windows平台)
Docker Desktop 是容器化应用开发与部署的一体化工具,支持本地创建、管理和运行 Docker 容器。4.38 版本新增 GPU 加速、WSL 2 性能优化和 Kubernetes 1.28 集群管理功能,适用于微服务开发和 CI/CD 流水线搭建。安装要求为 Windows 10 2004 及以上(64 位),需启用 Hyper-V 或 WSL 2。硬件最低配置为 4GB 内存、20GB 存储和虚拟化技术支持的 CPU。安装步骤包括启用系统功能、下载并运行安装程序,完成后配置镜像加速并验证功能。常见问题涵盖 WSL 2 安装不完整、磁盘空间清理及容器外网访问等。
655 11
|
4天前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
30 6
|
5天前
|
安全 固态存储 文件存储
Windows 7纯净版重装教程|附微软原版镜像下载+驱动安装避坑技巧
本文详细介绍如何安全、高效地重装电脑系统,解决蓝屏、崩溃等问题。基于10年经验,涵盖从官方镜像获取、启动盘制作、数据备份到系统部署的全流程,并针对老旧机型优化。提供驱动一键安装工具和系统激活指南,确保无后门风险。文中还列出常见问题解决方案及操作禁忌,帮助用户顺利完成系统重装,让电脑重获新生。建议收藏并转发给有需要的朋友,欢迎留言咨询疑难问题。
|
5天前
|
人工智能 测试技术 API
Windows用户必备:Postman v11详细安装指南与API测试入门教程(附官网下载
Postman是全球领先的API开发与测试工具,支持REST、SOAP、GraphQL等协议调试。2025年最新版v11新增AI智能生成测试用例、多环境变量同步等功能,适用于前后端分离开发、自动化测试、接口文档自动生成及团队协作共享API资源。本文详细介绍Postman的软件定位、核心功能、安装步骤、首次配置、基础使用及常见问题解答,帮助用户快速上手并高效利用该工具进行API开发与测试。
|
7天前
|
机器学习/深度学习 并行计算 PyTorch
Windows下CUDA+pytorch安装
以下是关于在Windows下安装CUDA和PyTorch的简要介绍及参考链接:
72 0
Windows下CUDA+pytorch安装
|
2月前
|
存储 Cloud Native Java
Windows下Minio的安装以及基本使用
MinIO 是一个开源的云原生分布式对象存储系统,兼容亚马逊S3接口,适合存储大容量非结构化数据。本文介绍Windows下MinIO的安装与基本使用:通过以上步骤,您可以在Windows环境中成功安装并使用MinIO。
374 17
|
3月前
|
关系型数据库 MySQL 数据库
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
在这一章节,主要介绍两个部分,数据库相关概念及MySQL数据库的介绍、下载、安装、启动及连接。接着,详细描述了MySQL 8.0的版本选择与下载,推荐使用社区版(免费)。安装过程包括自定义安装路径、配置环境变量、启动和停止服务、以及客户端连接测试。此外,还提供了在同一台电脑上安装多个MySQL版本的方法及卸载步骤。最后,解释了关系型数据库(RDBMS)的特点,即基于二维表存储数据,使用SQL语言进行操作,格式统一且便于维护。通过具体的结构图展示了MySQL的数据模型,说明了数据库服务器、数据库、表和记录之间的层次关系。
【MySQL基础篇】MySQL概述、Windows下载MySQL8.0超详细图文安装教程
|
3月前
|
安全 关系型数据库 MySQL
Windows Server 安装 MySQL 8.0 详细指南
安装 MySQL 需要谨慎,特别注意安全配置和权限管理。根据实际业务需求调整配置,确保数据库的性能和安全。
359 9
|
18天前
|
安全 Unix 虚拟化
Windows 7 & Windows Server 2008 R2 简体中文版下载 (2025 年 2 月更新)
Windows 7 & Windows Server 2008 R2 简体中文版下载 (2025 年 2 月更新)
42 11
Windows 7 & Windows Server 2008 R2 简体中文版下载 (2025 年 2 月更新)

热门文章

最新文章