程序的内存模型

125 阅读3分钟

1.1程序运行之前

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

(1)代码区:

存放CPU执行的机器指令(就是我们所写的所有代码的二进制形式)

特点:a.代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可。

b.代码区是只读的,使其只读的原因是防止程序意外地修改了它的指令。

(2)全局区:

全局变量和静态变量存放在此

全局区还包含了常量区,字符常量和其他常量也存放在此。该区域的数据在程序结束后由操作系统释放。

//创建全局变量,在main函数外面就是全局变量
int b = 10;
//const修饰的全局变量
const int g = 10;

int main() {
	
	//全局区:全局变量、静态变量、常量(const修饰的局部变量不是)
	//区分是否在全局区很简单,只需要输出地址是否在同一区域
	//创建局部变量
	int a = 10;

	//创建静态变量,在普通变量前面加static,属于静态变量
	static int c = 10;

	//常量:字符常量、const修饰的全局变量、const修饰的局部变量
	string m = "hello";
	const int h = 10;


	system("pause");

	return 0;
}

2.程序运行之后

栈区:

由编译器自动分配释放,存放函数的参数值,局部变量等。

注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放。

//栈区:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
int* function(int b) //形参存放在栈区
{
	//局部变量存放在栈区,栈区的数据在执行完成后自动释放
	int a = 10;
	//int b = 20;
	//返回局部变量的地址
	return &a;
}


int main() {
	
	//调用函数获取局部变量的地址
	int * p = function(20);
	//输出地址:第一次可以正常打印,是因为编译器做了保留
	cout << *p << endl;
	//第二次就无法正常打印了,会出现乱码
	cout << *p << endl;

	system("pause");

	return 0;
}

2.2堆区

由程序员分配释放,若程序员不释放,程序运行结束时由操作系统回收。

在c++中主要利用new在堆区开辟内存。

//堆区:
int * func() 
{
	//利用new关键字可以将数据开辟到堆区
	//指针本质上也是局部变量,放在栈上,指针保存的数据是存放在堆区
	int * p = new int(10);
	return p;
}


int main() {
	
	//在堆区开辟数据
	int * p = func();

	cout << *p << endl;
	cout << *p << endl;

	system("pause");

	return 0;
}

2.3 new操作符

c++中利用new操作符在堆区开辟数据

堆区开辟的数据,由程序员手动开辟,手动释放,释放利用操作符delete

语法:new 数据类型

注意:利用new创建的数据,会返回该数据对应的类型的指针.

//堆区:
int * func() 
{
	//利用new关键字可以将数据开辟到堆区
	//指针本质上也是局部变量,放在栈上,指针保存的数据是存放在堆区
	int * p = new int(10);
	return p;
}

//在堆区创建数组
void func2() {

	//在堆区利用new开辟数组,返回的是数组的首地址
	int * arr = new int[10];

	//对数组进行赋值
	for (int i = 0; i < 10; i++)
	{
		arr[i] = 10 + i;
		cout << arr[i] << endl;
	}

	//释放堆区数组,[]表明释放的是数组
	delete[] arr;
}


int main() {
	
	//在堆区开辟数据
	int * p = func();

	cout << *p << endl;
	cout << *p << endl;

	//释放堆区变量
	delete p;

	//cout << *p << endl; //没有权限访问,因为该地址已经被释放

	//调用数组函数
	func2();

	
	system("pause");

	return 0;
}