C++编程——内存详解

C++程序在执行时,将内存大方向划分为4个区域

  • 代码区:存放函数体的二进制代码,由操作系统进行管理的

  • 全局区:存放全局变量和静态变量以及常量

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

  • 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收

1.0 c++程序执行

C++程序编译运行的整个过程分为以下四个阶段:预处理、编译、汇编、连接。

  • 预处理:预处理器(cpp)对源程序中的伪指令和特殊符号进行展开,例如头文件的展开、宏定义展开、条件编译命令(#include、#define、#ifdef-#else-#endif等),得到展开后的C程序通常以 .i 为扩展名

  • 编译:编译器(ccl)进行词法分析、语法分析、语义分析等,将文本文件hello.i翻译成汇编文本文件hello.s

  • 汇编:汇编器(as)将汇编语言转换为机器语言,生成二进制文本hello.o

  • 连接:链接器(id)把所有的目标文件链接到一起,并生成最终的可执行文件hello.exe

1.1 程序运行前

程序编译时是不分配内存的,此时只是根据声明时的类型进行占位,到以后程序执行时分配内存。也就是说程序没有被加载到内存前,可执行程序内部已经分好3段信息,分别是代码区、数据区(data)和未初始化数据区(bss)三个部分。其中,数据区与未初始化数据区统称为全局区。在程序编译后,生成exe可执行文件。未执行该程序前程序分为两个区域

代码区:存放待执行的机器指令

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

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

全局区:存放全局变量、常量、静态变量

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

1.2 程序运行后

运行可执行程序,系统把程序加载到内存,除了根据可执行程序的信息分出代码区、数据区和未初始化数据区之外,还额外增加了栈区和堆区。

栈区:栈是一种先进后出的内存结构,由编译器自动分配释放, 存放函数的参数值,局部变量等。

堆区:堆是一个大容器,它的容量要远远大于栈,但没有栈那样先进后出的顺序。由程序员分配释放,若程序员不释放,程序结束时由操作系统回收。

示例:

#include <iostream>
using namespace std;

//全局变量--全局区
int global_a = 10;
int global_b = 10;

//全局常量--全局区
const int c_g_a = 10;
const int c_g_b = 10;

void test01()
{
	//局部变量--栈区
	int a = 10;
	int b = 10;

	//局部常量--栈区
	const int c_a = 10;
	const int c_b = 10;
	
	//静态变量--全局区
	static int s_a = 10;
	static int s_b = 10;

	cout << "全局变量 global_a 的地址为:" << &global_a << endl;
	cout << "全局变量 global_b 的地址为:" << &global_b << endl;

	cout << "全局常量 c_g_a 的地址为:" << &c_g_a << endl;
	cout << "全局常量 c_g_b 的地址为:" << &c_g_b << endl;

	cout << "局部变量 a 的地址为:" << &a << endl;
	cout << "局部变量 b 的地址为:" << &b << endl;

	cout << "局部常量 c_a 的地址为:" << &c_a << endl;
	cout << "局部常量 c_b 的地址为:" << &c_b << endl;

	cout << "静态变量 s_a 的地址为:" << &s_a << endl;
	cout << "静态变量 s_b 的地址为:" << &s_b << endl;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

输出结果

全局变量 global_a 的地址为:00EBC000
全局变量 global_b 的地址为:00EBC004
全局常量 c_g_a 的地址为:00EB9B30
全局常量 c_g_b 的地址为:00EB9B34
局部变量 a 的地址为:00FCFA10
局部变量 b 的地址为:00FCFA04
局部常量 c_a 的地址为:00FCF9F8
局部常量 c_b 的地址为:00FCF9EC
静态变量 s_a 的地址为:00EBC008
静态变量 s_b 的地址为:00EBC00C

1.3 new操作符

==new== 在堆区开辟数据存储空间

==delete== 释放堆区开辟的空间

语法:new 数据类型

**说明:**new开辟的空间在堆上,因此当在局部函数中new出一段新的空间,该段空间在局部函数调用结束后仍然能够使用,可以用来向主函数传递参数。

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

示例1:基本语法

new DataType( ) 分配这种类型的一个大小的内存空间,并以括号中的值来初始化这个变量;

int* test02()
{
	int* a = new int(10);
	return a;
}

int main()
{
	int* p = test02();
    
	cout << "堆区开辟变量的地址为:" << p << endl;
	cout << "堆区开辟变量的值为:" << *p << endl;
    
    delete p;	//释放堆数据
    
	system("pause");
    return 0;
}

输出结果

堆区开辟变量的地址为:0132C6E8
堆区开辟变量的值为:10

示例2:创建数组

new DataType[ ] 分配该类型n个大小的内存空间,并用默认构造函数来初始化这些变量;当使用new运算符定义一个多维数组变量或数组对象时,它产生一个指向数组第一个元素的指针。

int main()
{
	int* arr = new int[10];	//堆区开辟数组

	for (int i = 0; i < 10; ++i)
	{
		arr[i] = i;
		cout << arr[i] << " ";
	}

	delete[] arr;	//释放数组 delete 后加 []

	system("pause");
	return 0;
}

输出结果

0 1 2 3 4 5 6 7 8 9

示例3:创建二维数组

在C++中,数组可以被视为一种类型——但是,不存在‘二维数组’这种类型。二维数组本身会被解释成一个一维数组:这个数组的元素类型为另一种一维数组。比如int [2][3]这个二维数组,它会被编译器视作一个元素类型为‘int[3]’的一维数组。并且,‘int[3]’和'int[4]'会被当成不同的数据类型。

假设a, b为两个int型变量,如果你希望这样生成一个二维数组:new int[a][b],是不会得到编译器允许的——因为你没有指定这个数组的元素类型。如果将b指定为一个常量,例如new int[a][5],其实质与new int[a]创建一个动态数组并无多大区别——只是元素类型由int变为了'int[5]'而已。

void test03(unsigned int n)
{
	int(*arr)[4] = new int[n][4];
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			arr[i][j] = 4 * i + j;
			cout << *(*(arr + i) + j) << " ";
		}
		cout << endl;
	}
	delete[] arr;	// 回收方法和普通动态数组相同,使用'delete[]'即可
}
int main()
{
    test03(5);
	system("pause");
	return 0;
}

输出结果

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19

用这个方法来创建二维数组,比较直观、易用,但它最大的限制在于:你必须在编译时确定b的大小。更为实用的二维数组创建方法见参考博客 4 。

参考

  1. C/C++程序的编译过程_c++编译过程_Mindtechnist的博客-CSDN博客

  1. C/C++ 程序编译的四个阶段_c++文件编译与执行的四个阶段_wwxy261的博客-CSDN博客

  1. C++之new的详解_c++ new_柒笙歌的博客-CSDN博客

  1. C++用new创建二维数组的方法_c++ new数组_samuelcoulee的博客-CSDN博客

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值