C/C++内存管理

一、C++的内存分布

1.1 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";
 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);
}

C/C++内存管理
1、浅谈静态局部变量与全局变量的区别和联系。
区别:(1) 作用域不同,全局变量的作用域是全局,静态局部变量的作用域在该变量定义的区域内,出了该作用域不可被使用。
(2) 链接属性不同,若有多个文件使用全局变量时定义了相同名字的全局变量,此时会产生冲突,但是若多个文件都定义了相同名字的静态局部变量,因为其作用域不同,不会产生冲突。
联系:(1) 存储位置相同,全局变量和静态局部变量都存储在静态区中(即数据段区域)。
(2) 生命周期相同,全局变量和静态局部变量的生命周期都是从程序创建开始,到程序结束时销毁。
2、分析以下变量都存储在内存中的哪个位置

选项: A.栈 B.堆 C.数据段 D.代码段

globalVar在哪里?__ C__ 该变量为全局变量,存在数据段
staticGlobalVar在哪里?__ C__ 该变量为静态全局变量,存在数据段
staticVar在哪里?__ C__ 该变量为静态局部变量,存在数据段
localVar在哪里?__ A__ 该变量为局部变量,存在栈
num1 在哪里?__ A__ 该数组是局部变量,存在栈

char2在哪里?__ A__ 该数组是局部变量,存在栈
*char2在哪里?_ A __ * + 数组名表示数组首元素的值,由于char2是在栈上开辟空间之后,再将’abcd’的值拷贝到栈上开辟的空间中对char2进行初始化,因此char2解引用后所访问的值依旧在栈上。

pChar3在哪里?__ A__ 该变量时临时变量,存在栈区。
*pChar3在哪里?__ D__ *pChar3 解引用后指向的值是’abcd’,属于只读常量,存在代码段
ptr1在哪里?__ A__ 该变量是临时变量,存在栈区
*ptr1在哪里?__ B__ *ptr解引用后指向的变量时动态开辟的,动态开辟的空间在堆上。
3、分析sizeof 和 strlen的区别
sizeof(num1) = __ 40__; 计算数组的大小,开辟了10个int类型的数,大小是4 *10=40;
sizeof(char2) = __ 5__; 计算字符串’abcd’的长度,sizeof计算时要加上’\0’,因此是5个字节。
strlen(char2) = __ 4__;计算字符串’abcd’的长度,strlen计算时不加上’\0’,因此是4个字节。
sizeof(pChar3) = __ 4/8__; 计算指针的大小,可能是4字节或是8字节。
strlen(pChar3) = __ 4__;计算字符串长度,为4字节。
sizeof(ptr1) = __ 4/8__;计算指针的大小,可能是4字节或是8字节。

int main()
{
        char p1[] = "hello0";
        char p2[] = "hello\0";
        char p3[] = "hello\\0";
        char p4[] = "hello\\\0";

        cout<< sizeof(p1) << endl;
        cout<< sizeof(p2) << endl;
        cout<< sizeof(p3) << endl;
        cout<< sizeof(p4) << endl;
        
        cout<< strlen(p1) << endl;
        cout<< strlen(p2) << endl;
        cout<< strlen(p3) << endl;
        cout<< strlen(p4) << endl;
 }
        

C/C++内存管理

二、C++的内存管理方式

2.1 new和delete的操作内置类型

void Test()
{
 // 动态申请一个int类型的空间
 int* ptr4 = new int;

 // 动态申请一个int类型的空间并初始化为10
 int* ptr5 = new int(10);

 // 动态申请10个int类型的空间
 int* ptr6 = new int[3];

 delete ptr4;
 delete ptr5;
 delete[] ptr6;
}

C/C++内存管理
注:1、申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[]。
2、new的工作是先开辟空间,再调构造函数进行初始化;
delete的工作是先调析构函数清理空间,再释放空间。
3、new和delete,new[] 和 delete[],malloc,calloc,realloc和free,都必须匹配使用,不能new和free一起使用。

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

2.3 new和delete的实现原理
1、内置类型
如果申请的是内置类型的空间,new和malloc,delete和free基本类似,不同的地方是:new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间,而且new在申请空间失败时会抛异常,malloc会返回NULL。
2、 自定义类型
new的原理
(1) 调用operator new函数申请空间。
(2) 在申请的空间上执行构造函数,完成对象的构造。
delete的原理
(1) 在空间上执行析构函数,完成对象中资源的清理工作。
(2) 调用operator delete函数释放对象的空间。
new T[N]的原理
(1) 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请。
(2)在申请的空间上执行N次构造函数。
delete[]的原理
(1) 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。
(2) 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间。