从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(上)

简介: 从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题

1. C语言动态内存管理

1.1 C和C++内存分布

C和C++内存分布都是一样的。

栈区(stack)

       栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。

执行函数时,函数内部局部变量的存储单元都可以在栈上创建。

函数执行结束后这些存储单元会被自动释放。栈内存分配运算内置于处理器的指令集中,

拥有很高的效率,但是分配的内存容量是有限的。

栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。


堆区(heap)

       堆用于程序运行时动态内存分配,堆是可以上增长的。

一般由程序员自主分配释放,若程序员不主动不释放,程序结束时可能由操作系统回收。

其分配方式类似于链表。

数据段(data segment)

静态存储区,数据段存放全局变量和静态数据,程序结束后由系统释放。


代码段(code segment)

       可执行的代码 / 只读常量。代码段存放类成员函数和全局函数的二进制代码。

一个程序起来之后,会把它的空间进行划分,而划分是为了更好地管理。

函数调用,函数里可能会有很多变量,函数调用建立栈帧,栈帧里存形参、局部变量等等。

内存映射段(memory mapping)(了解)

       内存映射段是高效的I/O映射方式,用于装载一个共享的动态内存库。

用户可使用系统接口创建共享共享内存,做进程间通信。


结合以前的知识观察下面一段代码,并回答问题:

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
  static int staticVar = 1;
  int localVar = 1;
  int num1[10] = { 1, 2, 3, 4 };
  char char2[] = "abcd";
  const char* pChar3 = "abcd";
  int* ptr1 = (int*)malloc(sizeof(int) * 4);
  int* ptr2 = (int*)calloc(4, sizeof(int));
  int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
  free(ptr1);
  free(ptr3);
}

1. 选择题:

 选项 : A . 栈   B . 堆   C . 数据段 ( 静态区 )   D . 代码段 ( 常量区 )

 globalVar 在哪里? ____   staticGlobalVar 在哪里? ____

 staticVar 在哪里? ____   localVar 在哪里? ____

 num1 在哪里? ____

 char2 在哪里? ____   * char2 在哪里? ___

 pChar3 在哪里? ____       * pChar3 在哪里? ____

 ptr1 在哪里? ____         * ptr1 在哪里? ____

2. 填空题:

   sizeof(num1) = ____;

   sizeof(char2) = ____;    strlen(char2) = ____;

   sizeof(pChar3) = ____;   strlen(pChar3) = ____;

   sizeof(ptr1) = ____;


答案解析:


1.2 C语言中动态内存管理的方式

面试题1:malloc / calloc / realloc 的区别?

这三个函数我们以前学C语言已经学过了:

C语言进阶⑰(动态内存管理)四个动态内存函数+动态通讯录+柔性数组_GR C的博客-CSDN博客

相同点

  • 1.都是从堆上申请空间
  • 2.都需要对返回值判空
  • 3.都需要用户free释放
  • 4.返回值类型相同,都是void*
  • 5.都需要类型转化
  • 6.底层实现上是一样的,都需要开辟多余的空间,用来维护申请的空间

不同点:

  • 1.函数名字不同和参数类型不同。
  • 2.calloc会对申请空间初始化,并且初始化为0,而其他两个不会。
  • 3.malloc申请的空间必须使用memset初始化

4.realloc是对已经存在的空间进行调整,当第一个参数传入NULL的时候和malloc一样,调整分为两种情况:

① 调整的空间比原有空间大:

1.大了一点:要调整的多出来的空间小于原有空间后面空闲的空间,

做法:

1.1 直接延伸申请空间
1.2 返回原空间首地址**

2.大了很多:要调整的多出来的空间大于于原有空间后面空闲的空间,

做法:
2.1 重新开辟新空间
2.2 将旧空间的内容拷贝到新空间中
2.3 释放旧空间
2.4 返回新空间的首地址

  • ② 调整的空间比原有空间小:
    做法:
    1.将原空间缩小
    2 .返回旧空间首地址


面试题2:malloc的实现原理?(以下现在做简单了解)

从操作系统角度看,进程分配内存有两种方式,分别由两个系统调用完成:brk 和 mmap (不考虑共享内存)


brk 是将数据段(.data)的最高地址指针 _edata 往高地址推

mmap 是在进程的虚拟地址空间中(堆和栈中间,称为“文件映射区域”的地方)找一块空闲的虚拟内存

这两种方式分配的都是虚拟内存,并没有分配物理内存。在第一次访问已分配的虚拟地址空间的时候,会发生缺页中断,操作系统负责分配物理内存,然后建立虚拟内存和物理内存之间的映射关系、

情况一:malloc 小于 128K 的内存,使用 brk() 函数分配

情况二:malloc 大于 128K 的内存,使用 mmap 分配(munmap 释放)

一个拓展链接:【CTF】GLibc堆利用入门-机制介绍_哔哩哔哩_bilibili


2. C++动态内存管理方式

#include<iostream>
using namespace std;
 
int main()
{
  int* p1 = (int*)malloc(sizeof(int));
  int* p2 = (int*)malloc(sizeof(int) * 5);
 
  return 0;
}

C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦

(比如写链表的时候要多次申请空间),因此C++又提出了自己的内存管理方式:

通过newdelete操作符进行动态内存管理

2.1 new/delete操作内置类型

new/delete 的用法:

#include<iostream>
using namespace std;
 
int main()
{
  // 动态申请一个int类型的空间
  int* p1 = new int;
 
  // 动态申请一个int类型的空间并初始化为10
  int* p2 = new int(10);
 
  // 动态申请10个int类型的空间
  int* p3 = new int[10];
 
  //释放申请的空间,并置空
  delete p1;
  p1 = nullptr;
 
  delete p2;
  p2 = nullptr;
 
  delete[] p3;
  p3 = nullptr;
 
  return 0;
}

申请和释放单个元素的空间,使用 new delete 操作符,

申请和释放连续的空间, 使用 new[ ] delete[ ] ,注意:匹配起来使用。

是不是非常的方便,而且 new 不需要强制类型转换。

2.2 初始化new数组的问题

C++98 不支持初始化 new 数组:

int* p = new int[5];

但现在已经202X年了,C++11 允许大括号初始化,

我们就可以用 { } 列表初始化:(后面讲C++11还会讲这个语法)

int* p4 = new int[5] {1, 2};         // 1 2 0 0 0
int* p5 = new int[5] {1, 2, 3, 4, 5};  // 1 2 3 4 5

2.3 new 和 delete 操作自定义类型

       malloc / free 和 new / delete 对于内置类型没有本质区别,

那么它存在的意义是什么呢?仅仅是因为用法更简洁吗?

巨佬为了这么点事设计出来?可以但没必要,看看作用:

#include<iostream>
using namespace std;
 
class A
{
public:
  A(int a = 0)
    : _a(a)
  {
    cout << "A():" << this << endl;
  }
  ~A()
  {
    cout << "~A():" << this << endl;
  }
private:
  int _a;
};
 
int main()
{
  // new/delete 和 malloc/free最大区别是 new/delete对于【自定义类型】除了开空间
  //还会调用构造函数和析构函数
  A* p1 = (A*)malloc(sizeof(A));
  A* p2 = new A(1);
  free(p1);
  delete p2;
 
  // 内置类型是几乎是一样的
  int* p3 = (int*)malloc(sizeof(int)); // C
  int* p4 = new int;
  free(p3);
  delete p4;
 
  A* p5 = (A*)malloc(sizeof(A) * 10);
  A* p6 = new A[10];
  free(p5);
  delete[] p6;
 
  return 0;
}

new 不仅会开内存,还会调用对应的构造函数初始化,

相对的,free 只是把 p1 p2 指向的空间释放掉。

而 delete 不仅会释 p1 p2 指向的空间,delete 还会调用对应的析构函数。

new / delete 不仅仅是写法上变得简单了, 可以说就是为了自定义类型弄出来的。

(还有以后学的抛异常,下面讲operator new函数也简单的讲了一下)


new 对应的是 delete,可以可以 new 出来的用 free 释放?

不建议大家混着用, new 出来的用 free,有的编译器就会报错,

new[ ] 出来的 你去 delate 而不是 delete[ ]  也可能会报错。


总结:

在申请自定义类型的空间时,new 会调用构造函数,

delete 会调用析构函数,而 malloc 与 free 不会。

new:在堆上申请空间 + 调用构造函数输出。

delete:先调用指针类型的析构函数 + 释放空间给堆上。

匹配使用:malloc/free ,delete/delete ,new[ ] / delete[ ]

从C语言到C++⑨(第三章_C&C++内存管理)详解new和delete+面试题笔试题(中):https://developer.aliyun.com/article/1513662

目录
相关文章
|
5月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
202 26
|
10月前
|
存储 程序员 编译器
玩转C++内存管理:从新手到高手的必备指南
C++中的内存管理是编写高效、可靠程序的关键所在。C++不仅继承了C语言的内存管理方式,还增加了面向对象的内存分配机制,使得内存管理既有灵活性,也更加复杂。学习内存管理不仅有助于提升程序效率,还有助于理解计算机的工作原理和资源分配策略。
|
6月前
|
C语言 C++
c与c++的内存管理
再比如还有这样的分组: 这种分组是最正确的给出内存四个分区名字:栈区、堆区、全局区(俗话也叫静态变量区)、代码区(也叫代码段)(代码段又分很多种,比如常量区)当然也会看到别的定义如:两者都正确,记那个都选,我选择的是第一个。再比如还有这样的分组: 这种分组是最正确的答案分别是 C C C A A A A A D A B。
119 1
|
8月前
|
存储 NoSQL Redis
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
|
9月前
|
存储 Linux C语言
C++/C的内存管理
本文主要讲解C++/C中的程序区域划分与内存管理方式。首先介绍程序区域,包括栈(存储局部变量等,向下增长)、堆(动态内存分配,向上分配)、数据段(存储静态和全局变量)及代码段(存放可执行代码)。接着探讨C++内存管理,new/delete操作符相比C语言的malloc/free更强大,支持对象构造与析构。还深入解析了new/delete的实现原理、定位new表达式以及二者与malloc/free的区别。最后附上一句鸡汤激励大家行动缓解焦虑。
|
存储 缓存 C语言
【c++】动态内存管理
本文介绍了C++中动态内存管理的新方式——`new`和`delete`操作符,详细探讨了它们的使用方法及与C语言中`malloc`/`free`的区别。文章首先回顾了C语言中的动态内存管理,接着通过代码实例展示了`new`和`delete`的基本用法,包括对内置类型和自定义类型的动态内存分配与释放。此外,文章还深入解析了`operator new`和`operator delete`的底层实现,以及定位new表达式的应用,最后总结了`malloc`/`free`与`new`/`delete`的主要差异。
223 3
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
431 1
|
程序员 C语言 C++
【C语言基础】:动态内存管理(含经典笔试题分析)-2
【C语言基础】:动态内存管理(含经典笔试题分析)
|
程序员 编译器 C语言
【C语言基础】:动态内存管理(含经典笔试题分析)-1
【C语言基础】:动态内存管理(含经典笔试题分析)
|
Java 数据库连接 C语言
C语言进阶教程(内存分配常见问题分析)
C语言进阶教程(内存分配常见问题分析)
149 0