一文让你搞懂c++/c 内存分布

一. 计算机怎样识别代码的

现在大家编程中使用的都是高级语言,比如编译型c++,c等
脚本型语言JS,PHP,并且大家使用的都是集成开发环境(IDE),比如一些常见的DEV,vc++,VS等。
计算机是只能识别机器指令的,
也就是010010100,这些二进制数

大家有没有想过计算机是怎样处理并识别我们的代码的呢?

接下来,带你一起看看这其中的秘密:
这其中经历了几个阶段
在这里插入图片描述

1、预处理

1、首先第一步,我们使用的IDE会将代码进行预编译处理
1)所谓预编译处理就是将我们要使用的头文件,库文件拷贝过来,比如#include <iostream> #include <windows.h>等,这里的include
就是拷贝的意思 。

2)会把我们定义的宏进行替换,比如#define NUM 10,在进行预编译处理时,会把下文中的NUM替换成10;

2、编译

2、第二步就是进行我们的编译处理,所谓编译处理就是将我们的写的代码经过编译器把代码转换成汇编语言—>机器指令,得到目标文件,后缀为.obj

3、链接

3.最后一步就是==链接==,通过链接器来实现,链接就是把之前我们的源代码的文件和库文件,头文件所有整合在一起,最终形成一个可执行文件,一般是以.exe为后缀. 所以其实大家电脑上,手机上的桌面应用都是可执行文件,双击就可以执行.

二.代码在内存中是如何存储的

其实我们在IDE中写的代码是存放在内存中的,比如我们声明一个变量int a =10;内存中会为这个变量开辟存储空间,接下来我们就具体了解一下他是怎样存储的
首先来张图,内存分配 了这么几个部分(一般是分的内存四区,但这里我认为无所谓,多分了一个)
在这里插入图片描述

1、栈区

栈区:它的特点是由编译器在自动分配释放,存放函数的参数值和变量等,注意是针对函数
所谓自动分配释放指,比如我定义了一个函数,然后我再main函数中调用时,注意这里是调用时,内存会为在栈区分配空间,
这里我为什么会强调调用时,因为如果你只是声明定义了一个函数,并没有调用它,那么它里面的变量,形参就不会占用空间
在调用完后,系统会自动释放内存,即把函数里的变量全部清除。

1)栈溢出

这里顺便提一下栈溢出,大家平常遇到过栈溢出这个错误,所谓栈溢出,就是数据装不下。最典型的就是 1.递归调用的次数太多,因为我们每调用一次,在栈上就会分配一块存储空间,调用次数过多,就会空间不足,导致溢出, 2.还有就是我们如果声明的数组过大,也会导致栈溢出,因为我们的栈空间的内存一般大小为1-2M

2、堆区

特点是:随叫随到,挥之即走
堆区是我们程序员的自由天堂,也就是动态内存管理,内存为堆区分配的空间很大,通常有1-2G的大小。我们使用C语言中的malloc ,realloc函数,c++中的new,来申请释放内存比如申请一块内存空间,那么就会在堆上为你开辟。
挥之即去就是,我使用完之后,要手动删除,比如c的free,c++的delete,那么这段内存就不存在,不能再使用了。

int *salary=NULL;
salary =new int [10];//这里就是开辟一块数组
salary =new int(10)//也可不赋值 new int
//注意这里salary是接收的地址,访问时要注意
cout<<*salary<<endl;
delete []salary//即可删去
delete salary

最最最重要的两点是:
1.我们手动分配后一定要删除,否则会发生内存泄露,(即内存空间变小)
2如果你已经使用的delete删除了,后面就不能再访问

3、全局数据区

全取数据区是用来存储全局变量和静态变量的(static)。在函数的任意地方都可以访问,而我们在函数体内声明的变只能在这个函数内访问,出了这个函数,就不起作用力,比如下面的a只能在函数体内起作用,而year则不同,注意这里的静态变量是局部的,但是它是存放在全局数据区里面的

# include <iostream>
 using namespace std;
	 int year =10;
   void  print_t(int num){
     int a=10
	 static int b=num;
	 cout<<b<<endl;
	 cout<<a<<endl;
}
	int main(){
	print_t();
	
	static int a =10;
	return 0;
	}

这里的year和a,b放在全局数据区,还有一个要注意的是,如果我们在main函数多次调用print_t函数,且每次传入的实参不同,那么我们的b在第一次被赋值后就不会变了,不管你后面调用多少次
·

4、常量区

常量区就是存放我们代码中的常量,字符串常量等,这样做的目的是为了节省空间,避免重复申请内存。

include <iostream>

using namespace std;
int main() {
	const int a = 1000;
	int* ptr = (int*)&a;

	*ptr = 500;

	cout << *ptr << endl;
	cout << a << endl;

	return 0;

大家可以来执行这段代码,你们会发现一个奇怪的地方,我们用指针ptr接收了a的地址,并且修改了a的值,但是最后打印发现a的值还是1000, 大家可以思考为什么,欢迎在评论区留言

5 、代码区

存放函数体(包括类的成员函数,全局函数)的二进制代码

比如我们代码中的printf,scanf,cout,cin,system等这些指令,这里的代码区起的是控制作用。

本人才疏学浅,自己写的有不对的地方,欢迎大家指出

最后附上一个学院的b站二维码,里面很多视频是免费的,有很多大佬为你解答疑惑,还有很多活动,大家可以在这里进行交流

猜你喜欢

转载自blog.csdn.net/weixin_46273997/article/details/105268061