C++学习---动态内存

堆和栈

在C++中

  • 栈:是一种静态内存分配区域,用于存储局部变量和函数调用的上下文信息。在栈上的内存分配和释放都是自动管理的,遵循后进先出(LIFO)原则。
  • 堆:是一种动态内存分配区域,用于存储动态分配的数据,如对象、数据和数据结构等,在堆上的内存分配和释放需要显式管理,例如使用new或malloc操作符来分配内存,使用delete和free等操作符来释放内存。

在很多时候,你无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。

在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。

如果您不再需要动态分配的内存空间,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。


new和delete操作符

newdelete 运算符是C++中用于动态内存管理的操作符。它们允许你在堆上分配和释放内存,用于存储动态创建的对象和数据结构。

new 运算符:

  • new 运算符用于在堆上分配内存并构造一个对象。
  • 语法:new 数据类型new 数据类型[元素个数]
  • 对于单个对象的分配,new 返回指向该对象的指针。
  • 对于数组的分配,new 返回指向数组的首元素的指针。
  • 你需要手动释放使用 new 分配的内存,否则会导致内存泄漏。

例如,使用 new 创建一个整数对象的示例:

int* dynamicInt = new int; // 分配一个整数的内存
*dynamicInt = 42;

delete 运算符:

  • delete 运算符用于释放使用 new 分配的内存,并调用对象的析构函数(如果适用)。
  • 语法:delete 指针delete[] 指针
  • 你需要明确指定要释放的内存的指针,以避免悬挂指针问题。

例如,使用 delete 释放先前使用 new 分配的整数对象内存的示例:

delete dynamicInt; // 释放使用 new 分配的内存

newdelete 的数组形式:

你还可以使用 new[]delete[] 运算符来分配和释放动态数组的内存。在分配动态数组时,使用 new[],在释放内存时使用 delete[]。这些运算符对于分配和释放动态数组内存非常有用。

例如,使用 new[] 创建一个包含整数的数组,并使用 delete[] 释放内存的示例:

int* dynamicArray = new int[5]; // 分配一个包含 5 个整数的数组的内存
// 使用 dynamicArray 指向的内存
delete[] dynamicArray; // 释放使用 new[] 分配的数组内存

在C++中,可以通过检查指针是否为nullptr(空指针)来确定是否成功分配了内存。

例如:

int* dynamicInt = new int; // 尝试分配内存
if (dynamicInt != nullptr) {
    // 分配成功
    *dynamicInt = 42;
} else {
    // 分配失败
    // 执行错误处理逻辑
}

注:malloc() 函数在 C 语言中就出现了,在 C++ 中仍然存在,但建议尽量不要使用 malloc() 函数。new 与 malloc() 函数相比,其主要的优点是,new 不只是分配了内存,它还创建了对象。

完整的示例:

#include <iostream>

int main(){
    // 使用 new 分配内存并创建整数对象
    int* dynamicInt = new int;
    if (dynamicInt != nullptr){
        *dynamicInt = 42;
        std::cout << "Dynamic integer value: " << *dynamicInt << std::endl;
    } 
    else{
        std::cerr << "Memory allocation failed" << std::endl;
        return 1; // 退出程序,表示分配内存失败。
    }

    // 使用 delete 释放内存并销毁整数对象
    delete dynamicInt;

    return 0;
}

数组的动态内存分配

上面已经讲了关于new和delete的数组形式。扩展一下多维数组。

一维数组:

// 动态分配,数组长度为 m
int *array=new int [m];
 
//释放内存
delete [] array;

二维数组:

int **array;
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int [n];
}
//释放
for( int i=0; i<m; i++ )
{
    delete [] array[i];
}
delete [] array;

示例:

#include <iostream>

int main() {
    int numRows = 3;
    int numCols = 4;

    // 动态分配二维数组
    int** dynamicArray = new int*[numRows]; // 分配行指针数组
    for (int i = 0; i < numRows; i++) {
        dynamicArray[i] = new int[numCols]; // 分配每行的列数组
    }

    // 初始化二维数组
    int count = 1;
    for (int i = 0; i < numRows; i++) {
        for (int j = 0; j < numCols; j++) {
            dynamicArray[i][j] = count++;
        }
    }

    // 打印二维数组
    for (int i = 0; i < numRows; i++) {
        for (int j = 0; j < numCols; j++) {
            std::cout << dynamicArray[i][j] << ' ';
        }
        std::cout << std::endl;
    }

    // 释放动态分配的内存
    for (int i = 0; i < numRows; i++) {
        delete[] dynamicArray[i]; // 释放每行的列数组
    }
    delete[] dynamicArray; // 释放行指针数组

    return 0;
}

三维数组:

int ***array;
// 假定数组第一维为 m, 第二维为 n, 第三维为h
// 动态分配空间
array = new int **[m];
for( int i=0; i<m; i++ )
{
    array[i] = new int *[n];
    for( int j=0; j<n; j++ )
    {
        array[i][j] = new int [h];
    }
}
//释放
for( int i=0; i<m; i++ )
{
    for( int j=0; j<n; j++ )
    {
        delete[] array[i][j];
    }
    delete[] array[i];
}
delete[] array;

示例:

#include <iostream>

int main() {
    int x = 3;
    int y = 4;
    int z = 2;

    // 动态分配三维数组
    int*** dynamicArray = new int**[x]; // 分配 x 个二维数组
    for (int i = 0; i < x; i++) {
        dynamicArray[i] = new int*[y]; // 分配每个二维数组的 y 行
        for (int j = 0; j < y; j++) {
            dynamicArray[i][j] = new int[z]; // 分配每行的 z 列
        }
    }

    // 初始化三维数组
    int count = 1;
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < y; j++) {
            for (int k = 0; k < z; k++) {
                dynamicArray[i][j][k] = count++;
            }
        }
    }

    // 打印三维数组
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < y; j++) {
            for (int k = 0; k < z; k++) {
                std::cout << dynamicArray[i][j][k] << ' ';
            }
            std::cout << std::endl;
        }
    }

    // 释放动态分配的内存
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < y; j++) {
            delete[] dynamicArray[i][j]; // 释放每行的列数组
        }
        delete[] dynamicArray[i]; // 释放每个二维数组的行指针数组
    }
    delete[] dynamicArray; // 释放 x 个二维数组的指针数组

    return 0;
}

对象的动态内存分配

示例:

#include <iostream>
using namespace std;

class Box
{
    public:
        Box(){
            cout << "调用构造函数!" << endl;
        }
        ~Box(){
            cout << "调用析构函数!" << endl;
        }
};

int main()
{
    Box* myBoxArray = new Box[4];

    delete [] myBoxArray; // 删除数组

    return 0;
}

如果要为一个包含四个 Box 对象的数组分配内存,构造函数将被调用 4 次,同样地,当删除这些对象时,析构函数也将被调用相同的次数(4次)。

当上面的代码被编译和执行时,它会产生下列结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sciurdae

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值