C++之内存四区

一、内存四区

在计算机科学中,特别是在c或c++语言编程时,内存通常大致分为四个区域,而不同的区域存放的数据赋予不同的生命周期,给我们更大的灵活编程:

  1. 代码区:存储程序的可执行代码(二进制代码),也就是程序编译后的机器指令,通常是只读,防止运行时意外修改指令
  2. 全局区(数据区):存放全局变量和静态变量以及常量,这个区域在程序启动时被初始化,并且具有固定的内存分配
  3. 栈区:由编译器自动分配释放,存放函数调用时的局部变量、函数参数、返回地址等等,并且每次函数调用时栈都会增长,函数返回时,栈会收缩
  4. 堆区:堆区是程序运行时动态分配内存的区域,由程序员分配和释放,如果程序员不释放,程序结束时由操作系统回收

二、程序运行前

在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域:

  • 代码区:
  1. 存放cpu执行的机器指令(二进制代码)
  2. 代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在代码中有一份代码即可
  3. 代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令
  • 全局区(数据区):
  1. 全局变量和静态变量存放在此
  2. 全局区还包含了常量区,字符串常量和其他常量也存放在此
  3. 该区域的数据在程序结束后由操作系统回收

代码验证全局区:

int main()
{
	//静态变量
	static int a3;
	static int b3;
	//局部变量
	int a4;
	int b4;
	//局部常量
	const int a5=10;
	const int b5=10;
	//打印地址
	cout << "全局变量a1的地址:" << (int)&a1 << endl;
	cout << "全局变量b1的地址:" << (int)&b1 << endl;
	cout << "全局常量a2的地址:" << (int)&a2 << endl;
	cout << "全局常量b2的地址:" << (int)&b2 << endl;
	cout << "静态变量a3的地址:" << (int)&a3 << endl;
	cout << "静态变量b3的地址:" << (int)&b3 << endl;
	cout << "局部字符串常量a6的地址:" << (int)&"hello" << endl;
	cout << "局部字符串常量b6的地址:" << (int)& "hello" << endl;
	cout << "局部变量a4的地址:" << (int)&a4 << endl;
	cout << "局部变量b4的地址:" << (int)&b4 << endl;
	cout << "局部常量a5的地址:" << (int)&a5 << endl;
	cout << "局部常量b5的地址:" << (int)&b5 << endl;	
}
结果:
全局变量a1的地址:-868223152
全局变量b1的地址:-868223148
全局常量a2的地址:-868238320
全局常量b2的地址:-868238316
静态变量a3的地址:-868223144
静态变量b3的地址:-868223140
局部字符串常量a6的地址:-868238312
局部字符串常量b6的地址:-868238312
局部变量a4的地址:-1634731644
局部变量b4的地址:-1634731612
局部常量a5的地址:-1634731580
局部常量b5的地址:-1634731548

根据结果显示的地址距离不难发现全局区存放有:全局变量、静态变量(static修饰)、常量(字符串常量、全局常量(const修饰)),而局部变量和局部常量(const修饰)都不在全局区中

总结:

  • c++中在程序运行前分为全局区和代码区
  • 代码区特点是共享和可读
  • 全局区中存放全局变量、静态变量、常量
  • 常量区中存放const修饰的全局常量和字符串常量

三、程序运行后

栈区:

  • 由编译器自动分配释放,存放函数的形参、局部变量、返回地址等
  • 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

代码举例:

int* func(int a)//形参
{
	int b = a;//局部变量
	return &b;//返回地址
}
int main()
{
	int*p =func(10);
	cout << *p << endl;
	cout << *p << endl;
}
结果:
10
2297916

由前文知func函数中的数据都在栈区当中,当这个函数执行结束之后内存就自动释放了,但是编译器会对返回的地址会做一次保留,所以第一次输出时就是10,但是第二次就是一个随机值了,所以证明了不能返回局部变量的地址,这会造成野指针的问题

堆区:

  • 由程序员分配和释放,如果程序员不释放,程序结束时就由操作系统回收
  • 在c++中主要利用new关键字在对堆区开辟空间

代码举例:

int* func(int a)//形参
{
	//利用new关键字将数据开辟到堆区
	//这里的指针p本质也是局部变量,放在栈上,但是指针保存的数据是放在堆区的,所以返回的值也是在堆区
	int *p=new int(a);
	return p;//返回地址
}
int main()
{
	int*p =func(10);
	cout << *p << endl;
	cout << *p << endl;
}

四、new操作符

在c++中,主要用new操作符在堆区开辟空间,堆区开辟的数据由程序员手动开辟和释放,而释放就要利用操作符delete,利用new 创建的数据会返回一个指向该数据类型的指针(地址),下面是代码介绍语法:

class p//定义类
{
	public:
	p()
	{
		cout<<"默认构造函数的调用"<<endl;
	}
	~p()
	{
		cout<<"析构函数的调用"<<endl;
	}
}
int main()
{
	//分配单个对象
	int* p1 = new int;//在堆分配一个int类型的内存并返回其指针
	//分配数组
	int* arr = new int[10];//分配一个包含10个整型的数组
	//初始化对象
	int* p2 = new int(5);//利用new开辟空间时可以顺便初始化整型为5
	//分配并构造对象
	p* p3=new p();
	//释放内存
	delete p1;
	delete p2;
	delete []arr;
	delete p3;
}

注意事项:

  • 每次调用new操作符都应该有一个对应的delete或delete[]操作符来释放内存
  • 忘记释放内存将会导致内存泄漏
  • 注意区分分配数组和单个对象的区别,并且在释放内存时也有所区别
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值