1.了解一些基本的内存段(图演示)

验证栈是向下生长的

1

2

3

4

5

6

7

8

9

10

11

12

13

14

#include<iostream>

using namespace std;

int main()

{

    int a = 3;

    int b = 4;

    int c = 5;

    int d = 6;

    cout <<"a:"<< &a << endl;

    cout << "b:"<<&b << endl;

    cout << "c:"<<&c << endl;

    cout << "d:"<<&d << endl;

    return 0;

}

验证堆一般是向上生长的(不一定)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

#include<iostream>

using namespace std;

int main()

{

    int num = 10;

    while (num--)

    {

        int *p1 = (int*)malloc(sizeof(int));

        int *p2 = (int*)malloc(sizeof(int));

        cout <<"p1"<< p1 << endl;

        cout <<"p2"<<p2 << endl;

        cout << endl;

        free(p1);

    }

    return 0;

}

一般情况下,p1的地址是比p2的地址高的(因为堆一般是向上生长的),但是有时候是不一定的。

巩固内存管理知识点

答案

温馨提示:题目中的指针是局部指针变量,是在栈上的,但是它指向的内容(解引用)可能是堆区或者常量区的。,可以画画图理解理解

2.c++申请动态内存的新玩儿法new,delete

回顾c语言动态内存管理的方式

malloccallocrealloc

  • malloc堆上动态开空间
  • calloc堆上动态开空间+初始化成0等价于malloc+memset
  • realloc指针已有的空间扩容

原题增容–后面又足够的空间

异地增容–后面没有足够的空间

开辟内置类型的空间

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

//C++开辟动态内存的新玩法

//语法演示:

#include<iostream>

using namespace std;

int main()

{

    //申请一个int的动态空间

    int* p1 = (int*)malloc(sizeof(int));

    *p1 = 1;

    int* p2 = new int(2);//这里是初始化

    free(p1);

    delete p2;

    //申请一个10各int的动态数组

    int *p3 = (int*)malloc(sizeof(int)* 10);

    for (int i = 0; i < 10; i++)

    {

        p3[i] = i + 1;

    }

    int *p4 = new int[10]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};//初始化

    free(p3);

    delete[]p4;

    return 0;

}

跟c语言的版本相比,c++的版本,初始化时显得比较方便,而且语法比较简洁。当然了,更大的优越性还在后面。

开辟自定义类型的空间(请用vs2013以上版本测试代码)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

#include<iostream>

using namespace std;

struct ListNode

{

    int _val;

    ListNode* _next;

    ListNode* _prev;

    //构造函数

    ListNode(int val = 0)

    :_val(val)

    , _next(nullptr)

    , _prev(nullptr)

    {

        cout<<"ListNode(int val = 0)"<<endl;

    }

    ~ListNode()

    {

        cout << "ListNode()" << endl;

    }

};

int main()

{

    //申请一个结点的空间

    ListNode* pa = (ListNode*)malloc(sizeof(ListNode)*4);

    ListNode* pb = new ListNode(1);//不用去用sizeof去计算空间大小,很方便  

    free(pa);

    delete pb;

    //申请4个结点的空间--当然了一般不会这么玩儿,我们只是看看效果

    ListNode* pc = (ListNode*)malloc(sizeof(ListNode)* 4);

    ListNode* pd = new ListNode[4]{1, 2, 3, 4};

    free(pc);

    delete[]pd;

    return 0;

}

​ 学过c语言版本的数据结构的小伙伴都知道,我们push_back一个结点时,需要先实现一个buynewnode的函数(创建一个结点,并且对其进行初始化)。而new这个操作符,在创建结点的同时,已经帮我们实现了结点的初始化。调用了构造函数,而且delete还调用了析构函数。

总结一下

  1. c++中,如果是申请内置类型对象或者数组,mallocnew没有太大区别
  2. 如果时自定义类型,区别很大,new和delete时开空间+初始化,析构清理+释放空间,mallocfree仅仅时开空间+释放空间
  3. 建议在c++中,无论时内置类型还是自定义类型的申请释放,尽量使用new和delete。

3. 32位平台下可以开辟多大的内存

我:cpu过来遭罪

cpu:你不要过来啊

上述程序,我们开了1.8 G左右的内存,加上需要堆上的小内存,最后的综合有2 G的空间

如何开辟4G的内存

将项目属性修改一下,改成64位平台即可,64位平台有2^34 G的空间(虚拟内存)在这我们不做细说,因为我也不太了解Linux。

4.了解operator new和operator delete

new其实是operator new + 构造函数

delete其实是operator delete+构造函数

newdelete是用户进行动态内存申请和释放的操作符,operator newoperator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间

大家可以将operator new和operator delete理解成和malloc 和free一样用法的函数。

唯一不同的地方是,operator new和malloc开辟空间失败的处理方式不一样,malloc是返回NULL空指针,而operator是抛异常,下面代码让大家看看效果,不必深究,以后会有介绍。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐