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.内存划分题
题解:
内存区域划分:
【说明】
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题
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指向那块空间已经属于操作系统了,这时候再操作就引发野指针异常
⭕ 【面试题】
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; }
对于内置类型的详细例子
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[],注意:匹配起来使用!!!
还需注意的是:
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; }
自定义类型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没有办法很好地支持动态申请的对象初始化
new的使用:开空间,加构造函数初始化
int main() { A* p2 = new A; //0也是初始化,如果没有初始化就是随机值了 A* p3 = new A(3); }
执行:
delete的使用:自定义类型,调用析构函数+释放空间
int main() { //开空间,加构造函数初始化 A* p2 = new A; A* p3 = new A(3); //调用析构函数+释放空间 delete p2; delete p3; }
调用默认构造初始化
int main() { A* p4 = new A[10]; delete[] p4; }
调用显示构造初始化
int main() { A aa1(2); A aa2(3); A* p5 = new A[10]{ aa1,aa2 };//使用有名对象进行数组初始化 delete[] p5; }
使用了匿名对象进行数组初始化
int main() { A* p6 = new A[10]{ A(1),A(2)};//使用了匿名对象进行数组初始化 delete[] p6; }
使用int型数据进行数组初始化
总结:
在申请自定义类型的空间时,new会调用构造函数,delete会调用析构函数, 而malloc与 free不会
【C++初阶】第五站:C/C++内存管理 (匹配使用,干货到位)-2