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);
}
选择题:
选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?(C)
staticGlobalVar在哪里?(C) 全局,生命周期全局
staticVar在哪里?(C) 局部,生命周期全局
localVar在哪里?(A)
num1在哪里?(A) 数组名,数组/数组首元素地址,局部变量,存在栈中
char2在哪里?(A) 是一个局部的数组,
*char2在哪里? (A) 是指向首元素本身的,在栈中
pChar3在哪里?(A) 局部变量
*pChar3在哪里? (D) const修饰指针变量
ptr1在哪里?(A) 局部变量的指针
*ptr1在哪里?(B) 动态开辟mallco(),需要手动释放
栈,堆,数据段(静态区) ,代码段(常量区)
栈是向下生长的,堆是向上生长的
void Test ()
{
// 1.malloc/calloc/realloc的区别是什么?
int* p2 = (int*)calloc(4, sizeof (int));
int* p3 = (int*)realloc(p2, sizeof(int)*10);
//2,这里需要free(p2)吗?
free(p3 );
}
1,malloc/calloc/realloc的区别?
calloc会初始化为0,realloc会对空间扩容,原地扩容,异地扩容(程序在堆区开辟相应大小扩容,如果大
小不够,在另一个地方开辟总大小的空间,将内容拷贝,释放旧空间)
三者开辟的空间可以通过free释放。
2,在C语言中,使用realloc
重新分配内存时,其行为决定了是否需要手动释放原指针:
realloc
成功时的两种情况:
realloc
会直接扩展内存,返回的指针p3
与原指针p2
相同。此时只需free(p3)
即可,原指针p2
已失效,无需操作。realloc
会分配新内存、复制数据,并自动释放原内存块。此时p2
指向的内存已被释放,若再free(p2)
会导致双重释放(Undefined Behavior)。realloc
失败时:
NULL
,此时原指针p2
仍有效。若直接free(p3)
(即free(NULL)
,无害但无操作),会导致p2
内存泄漏。正确做法是检查返回值,若失败则保留并处理p2
。但是最好在此处判断一下realloc是否成功,如果不成功则还是需要手动释放,但是一般情况下realloc是不会失败的
void Test() {
int *p2 = (int*)calloc(4, sizeof(int));
int *p3 = (int*)realloc(p2, sizeof(int)*10);
// realloc失败时,p3为NULL,此时p2仍有效
if (p3 == NULL) {
free(p2); //处理失败情况,释放原内存
return;
}
free(p3); //成功时只需释放新指针
}
申请和释放单个元素的空间,使用new和delete操作符
申请和释放连续的空间,使用new[]和delete[]
注意:匹配起来使用。
void Test()
{
// 动态申请一个int类型的空间,默认不会初始化(有些环境也可能会)
int* ptr1 = new int;
// 动态申请一个int类型的空间并初始化为10
int* ptr2 = new int(10);
// 动态申请10个int类型的空间
int* ptr3 = new int[3];
int* ptr3 = new int[4]{1,2,3,4};
delete ptr1;
delete ptr2;
delete[] ptr3;
}
比如使用 char* p = new char[100]申请一段内存,然后使用delete p释放,有什么问题?( )
不会有内存泄露,对于内置类型,程序不会崩溃,但不建议这样使用
编译不会报错,建议针对数组释放使用delete[],如果是自定义类型,不使用方括号就会运行时错误
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会调用构造函数,delete会调用析构函数,而malloc与free不会。
处理错误方式不同:
malloc失败是返回空
new失败的机制是抛异常,如果直到main函数也没有捕获(使用try和catch),会直接报错
#include
using namespace std;
int main()
{
size_t x = 0;
int* ptr = nullptr;
do
{
//ptr = (int*)malloc(10 * 1024 * 1024);
if (ptr)
x += 10 * 1024 * 1024;
cout << ptr << endl;
} while (ptr);
cout << x << endl;
cout << x / (1024 * 1024) << endl;
return 0;
}
两个全局的库函数
new和delete是用户进行动态内存申请和释放的操作符**,**operator new和operator delete是
系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过
operator delete全局函数来释放空间。
使用operator new封装malloc,实现开辟空间失败时,抛出异常,而非返回空给出错误码
通过上述两个全局函数的实现知道,operator new实际也是通过malloc来申请空间,如果
malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施
就继续申请,否则就抛异常。operator delete最终是通过free来释放空间的。
在申请内置类型的空间时,new和malloc,delete和free的语法基本类似,不同的地方是:
1,new/delete申请和释放的是单个元素的空间,new[]和delete[]申请的是连续空间。
2,new在申请空间失败时会抛异常,malloc会返回NULL。
new的原理
1,调用operator new函数申请空间。
2,在申请的空间上执行构造函数,完成对象的构造。
operator delete: 该函数最终是通过free来释放空间的
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来释放空间