【C++初阶】第五站:C/C++内存管理 (匹配使用,干货到位)-1

简介: 【C++初阶】第五站:C/C++内存管理 (匹配使用,干货到位)-1

C/C++内存分布

我们先来看下面的一段代码和相关问题


代码示例:


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.内存划分题


203e195b4ee44467b2b51fe5cf765293.png


题解:


0b477e09525f4700aa33db5d03b5aa50.png


内存区域划分:


f82b8d473ebf42ffbe4f1ba13e99a58b.png


【说明】


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


2.内存映射段是高效的 I/O 映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。(未学到linux仅作了解即可)


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


4.数据段--存储全局数据和静态数据。


5.代码段--可执行的代码/只读常量。


2.sizeof 和 strlen 区别?

这篇文章有详细的总结 --> 指针进阶(3) -- 关于sizeof和strlen的详细总结


在C/C++中:
sizeof:这是一个运算符,编译时确定,用于计算变量或类型的大小(以字节为单位),包括数组、指针、结构体等。对于字符数组或字符串,它返回整个数组(包括结束符 \0)的总字节数。
strlen:这是一个库函数,运行时确定,用于计算以 \0 结尾的字符串的实际字符数,不包括结束符 \0。因此,对于包含字符串的字符数组,strlen 返回的是字符串的有效字符数量。
简单地说:
sizeof 计算内存容量;
strlen 计算字符串长度。

3.计算sizeof和strlen题

edc4efe42dde4909a8dcbf28bbfd8e18.png


C语言中动态内存管理方式:malloc/calloc/realloc/free

malloc/calloc/realloc和free

#include<stdio.h>
#include<malloc.h>
int main()
{
  int* p1 = (int*)malloc(sizeof(int));
  free(p1);
  int* p2 = (int*)calloc(4, sizeof(int));
  // 这里需要free(p2)吗?
  //free(p2);
  int* p3 = (int*)realloc(p2, sizeof(int) * 10);
  free(p3);
}

为什么不需要free(p2)?


       因为p2申请了四个字节的空间,此基础上,如果free掉p2,那么p3申请空间的时候,p2指向那块空间已经属于操作系统了,这时候再操作就引发野指针异常


32035da14c7243b69eb02a448df30ae0.png


⭕ 【面试题】

1. malloc/calloc/realloc的区别?

malloc:
功能:动态分配指定字节数的内存。
特点:不会初始化分配的内存,内容随机。
语法:void* malloc(size_t size);
示例:int *p = (int*)malloc(sizeof(int)*n); 分配n个整数大小的连续内存空间。
calloc:
功能:动态分配指定数量、特定类型的内存空间,并初始化为0。
特点:不仅分配内存,还会清零初始化。
语法:void* calloc(size_t num, size_t size);
示例:int *p = (int*)calloc(n, sizeof(int)); 分配并初始化n个整数大小的连续内存空间为0。
realloc:
功能:调整已分配内存块的大小,可以扩大或缩小。
特点:如果扩大内存,新增空间内容不确定;如果缩小内存,多余部分会被释放,缩小后的内存区域保持不变。
语法:void* realloc(void* ptr, size_t new_size);
示例:int *new_p = (int*)realloc(p, sizeof(int)*m); 尝试更改指针p指向的内存区域大小为m个整数所需空间,返回新的内存地址,有可能与原地址相同也可能不同。
总的来说:
malloc 用于单纯分配未初始化的内存。
calloc 用于分配并初始化为零的内存。
realloc 用于调整已分配内存区域的大小,提供了一种灵活的内存管理手段。

更多详细内容请移步到 --> 【C进阶】-- 动态内存管理


C++内存管理方式

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

此C++又提出了自己的内存管理方式:通过 new和delete 操作符进行动态内存管理。

new/delete操作内置类型

 内置类型是几乎是一样的:

malloc和new对于内置类型都 只会申请空间但不会初始化 ,因为 new没有调构造函数
同样对于delete和free来说,都只会释放对象的空间, delete不会调用析构函数
int main()
{
     int* p3 = (int*)malloc(sizeof(int)); // C
     int* p4 = new int;//这个地方还是随机值(内置类型不会调构造)
     free(p3);
     delete p4;
}


9699225a9b45424fb9517822a3ee08ff.png

                                                    对于内置类型的详细例子


include<stdio.h>
#include<malloc.h>
#include<iostream>
using namespace std;
int main()
{
  //不会初始化的例子
     int* p2 = (int*)malloc(sizeof(int));
  //自动计算大小,不需要强转,动态申请一个int类型的空间
     int* p3 = new int;
  //动态分配一块足够存储 10 个整数的连续内存空间
     int* p4 = (int*)malloc(sizeof(int) * 10);
  // 动态申请10个int类型的空间
     int* p5 = new int[10];
  //malloc的释放方式
     //free(p2);
     //free(p4);
  //new的释放方式
     //delete p3;
     //delete[] p5;
  //会初始化的例子
  //额外支持空间 + 初始化
  //动态申请一个int类型的空间
     int* p6 = new int(10);
  // 动态申请10个int类型的空间,并初始化前三个
     int* p7 = new int[10]{ 1,2,3 };
  // 动态申请10个int类型的空间
     int* p8 = new int[10]{};
  return 0;
}


注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用 new[]和delete[],注意:匹配起来使用!!!


还需注意的是:



086628022cec4622a7443ce58fec517e.png

new和delete操作自定义类型

new/delete 和 malloc/free 最大区别是:

new/delete  对于【自定义类型】除了 开空间 /释放空间 ,还会调用 构造函数和析构函数

示例:

int main()
{
  A* p1 = (A*)malloc(sizeof(A));
  A* p2 = new A(1);
  free(p1);
  delete p2;
}

1777f7bdb8b347feb7f25cff4619d7db.png

自定义类型A,代码示例:


class A
{
public:
  A(int a=0)
  :_a(a)
  {
  cout << "A()" << endl;
  }
  ~A()
  {
  cout << "~A()" << endl;
  }
private:
  int _a;
};
int main()
{
  //malloc没有办法很好地支持动态申请的对象初始化
  A* p1 = (A*)malloc(sizeof(A));
}


malloc没有办法很好地支持动态申请的对象初始化



80939becf3be44a980afce34bfc784c4.png

e79e4787c49445b0a58dec6d7e3fad80.png 44852884dc304219bb3a9dfe437ef64a.png



new的使用:开空间,加构造函数初始化

int main()
{
    A* p2 = new A; //0也是初始化,如果没有初始化就是随机值了
    A* p3 = new A(3);
}

执行:


99c3925323734c80a25875af5c3bed50.png


delete的使用:自定义类型,调用析构函数+释放空间

int main()
{
//开空间,加构造函数初始化    
    A* p2 = new A;
  A* p3 = new A(3);
//调用析构函数+释放空间
  delete p2;
  delete p3;
}


139f0b7856db4ddfb87a400dd7a2fbde.png

调用默认构造初始化

int main()
{
    A* p4 = new A[10];
  delete[] p4;
}



9b3bf1d14cea48f0b4740d8b67cbf47d.png

调用显示构造初始化

int main()
{
    A aa1(2);
  A aa2(3);
  A* p5 = new A[10]{ aa1,aa2 };//使用有名对象进行数组初始化
  delete[] p5;
}


04dc0963a06549508b7a3496115062b6.png

使用了匿名对象进行数组初始化

int main()
{
    A* p6 = new A[10]{ A(1),A(2)};//使用了匿名对象进行数组初始化
  delete[] p6;
}



使用int型数据进行数组初始化


b2e65b8fa57449f1bb2a4b09009a96dc.png


总结:


   

在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数,
        而malloc与 free不会



【C++初阶】第五站:C/C++内存管理 (匹配使用,干货到位)-2

https://developer.aliyun.com/article/1457043

相关文章
|
5天前
|
编译器 C语言 C++
c++初阶------类和对象(六大默认构造函数的揭破)-3
c++初阶------类和对象(六大默认构造函数的揭破)
|
5天前
|
编译器 C语言 C++
c++初阶------类和对象(六大默认构造函数的揭破)-2
c++初阶------类和对象(六大默认构造函数的揭破)
|
5天前
|
存储 编译器 C语言
c++初阶-------类和对象-2
c++初阶-------类和对象
|
5天前
|
安全 编译器 C语言
C++初阶------------------入门C++(三)
C++初阶------------------入门C++(三)
|
5天前
|
存储 Linux 编译器
C++初阶------------------入门C++(二)
C++初阶------------------入门C++(二)
|
5天前
|
编译器 C语言 C++
C++初阶------------------入门C++(一)
C++初阶------------------入门C++(一)
|
12天前
|
存储 缓存 算法
C++从入门到精通:4.6性能优化——深入理解算法与内存优化
C++从入门到精通:4.6性能优化——深入理解算法与内存优化
|
12天前
|
存储 程序员 编译器
C++从入门到精通:3.4深入理解内存管理机制
C++从入门到精通:3.4深入理解内存管理机制
|
12天前
|
存储 人工智能 程序员
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
【重学C++】【内存】关于C++内存分区,你可能忽视的那些细节
44 1
|
12天前
|
存储 编译器 对象存储
【C++基础(十)】C++泛型编程--模板初阶
【C++基础(十)】C++泛型编程--模板初阶
【C++基础(十)】C++泛型编程--模板初阶