导语:内存四区模型是非常重要的一个知识,只有学会从编译器的角度去了解内存是如何分配的,在遇到问题的时候,才能更好的去分析
在掌握四驱模型之前,需要理解几个重要的概念
1.数组参数传递
问题:数组作为参数传递的时候,为什么获取不到长度?
答:数组作为参数传递,会退化成一个指针,传递的是首地址,目的是为了高效。因此在使用数组作为参数时,通常会将长度也作为参数传进去。
2.数据类型
数据类型的本质:内存上一块连续的固定大小空间的别名
3.变量的本质
一段连续内存空间的别名,通过变量可以去操作一块内存上的数据
4.内存四区建立过程
1.操作系统将程序从物理磁盘中load进内存里(运行.exe文件)
2.操作系统把c代码分成四个区
3.操作系统找到main函数入口执行程序
5 四区分析
- 栈区:由编译器自动分配释放,存放函数的参数、局部变量值等
- 堆区:一般由程序员分配与释放(malloc、free等函数操作),若程序员不释放,在结束后可能由操作系统进行回收
-数据区:存放全局变量、静态变量和常量字符串等等,程序结束后由系统进行释放
-代码区:存放函数体的二进制代码
6 具体分析
1.数据区
#include<stdio.h>
char* getStr1() {
char* str1 = "hello";
return str1;
}
char* getStr2() {
char* str2 = "hello";
return str2;
}
void main() {
char* str1 = getStr1();
char* str2 = getStr2();
printf("str1的内存地址是:%p str2的内存地址是:%p \n", str1, str2);
printf("str1的值是:%s str2的值是:%s", str1, str2);
}
结果输出
str1的内存地址是:00627B30 str2的内存地址是:00627B30
str1的值是:hello str2的值是:hello
image.png
当执行getStr1()方法时,是在数据区当中拿到字符串常量”hello“的地址,并将它赋值给指针str1。可以理解为 str1是数据区 一块内存(内存上的数据为”hello“)的别名。同理 执行getStr2()的时候 同样将该常量的地址赋值给指针str2。
getStr1()和getStr2()方法执行完之后,在main函数中用str1和str2 两个变量来接收返回的指针,即将str1和str2指针都指向到了数据区”hello“字符串的地址 ,因此通过打印可以看出 两个指针的地址相同,数据也相同。
char* str1 = getStr1();
char* str2 = getStr2();
image.png
2.栈区的理解
栈区的内存由编译自动分配与释放
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* getStr() {
char buf[64];
strcpy(buf, "hello");
return buf;
}
void main() {
char* str = getStr();
printf("str的内存地址是:%p str的值是:%s \n", str, str);
}
结果:
str的内存地址是:00EFF914 str的值是:烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫\
在这个例子里,发现str的值是乱码,这是由于方法结束时,会将方法内的栈区的内存数据给清空,但地址仍然存在。我们同样画图分析
image.png
在getStr方法中,我们调用strcpy方法,其实是往buf所在的内存中写入数据。但此时,buf指向的仍是栈区内内存。在getStr方法执行完return之后,方法结束,栈区内即buf所指向的内存区域数据清除,但buf仍代表着一个地址,并将这个地址赋值给了main()函数中的str指针,因此该指针有地址,但数据是乱码。
3.堆区
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* getStr() {
char* p1 = NULL;
p1 =(char*) malloc(sizeof(char) * 10);//申请了十个字符大小的内存空间
if (p1 == NULL) {
return NULL;
}
}
void main() {
char* str = getStr();
if (str == NULL) {
printf("str的内存地址是NULL");
}
else
{
strcpy(str, "0123456789");
printf("str的内存地址是:%p str的值是:%s \n", str, str);
}
}
结果:
str的内存地址是:006257C0 str的值是:0123456789
image.png
通过malloc函数在堆区中申请了一段大小为10的内存,p1指针指向了该地址,是该块内存的别名。在getStr()函数结束之后,将指针所指向的地址又赋值给了str,因此str指针也指向了堆区中的这块内存地址
image.png
网友评论