一、程序的内存四区模型
流程说明
1、操作系统把物理硬盘代码load到内存
2、操作系统把c代码分成四个区
3、操作系统找到main函数入口执行
1.栈区和堆区
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *get_str()
{
char str[] = "abcdedsgads"; //栈区,
printf("str = %s\n", str);
return str;
}
char *get_str2()
{
char *tmp = (char *)malloc(100);
if (tmp == NULL)
{
return NULL;
}
strcpy(tmp, "adsagldsjglk");
return tmp;
//注意 return不是把内存块 64个字节,给return出来
//而是把内存块的首地址(比如内存的编号0xaa11) ,返回给 p
// 理解指针的关键是内存,没有内存哪里来的指针
}
int main(void)
{
char buf[128] = { 0 };
// strcpy(buf, get_str()); //此处可能是拷贝完在释放(结果是str的值)
// printf("buf = %s\n", buf); //乱码,不确定
// char *p1 = NULL;
// p1 = get_str();
// printf("p1 = %s\n",p); //此时一定不对
char *p = NULL;
p = get_str2();
if (p != NULL)
{
printf("p = %s\n", p);
free(p); //解除p与地址的指向关系
p = NULL;
if (p != NULL)
{
free(p);
}
}
p = adsagldsjglk
栈区:
堆区:
2.全局区
#include <stdio.h>
char *get_str1()
{
char *p = "abcdef1"; //文字常量区
return p;
}
char *get_str2()
{
char *q = "abcdef2"; //文字常量区
return q;
}
int main(void)
{
char *p = NULL;
char *q = NULL;
p = get_str1();
//%s: 指针指向内存区域的内容
//%p: 打印p本身的值
printf("p = %s, p = %p\n", p, p);
q = get_str2();
printf("q = %s, q = %p\n", q, q);
printf("\n");
return 0;
}
~
p = abcdef1, p = 0x55d52b31d004
q = abcdef2, q = 0x55d52b31d00c
内存四区图:
二、函数的调用模型
三、函数调用变量传递分析
- main函数中可以在栈/堆/全局分配内存,都可以被func1和func2使用
- func2在栈上分配的内存,不能被func1和main函数使用
- func2中malloc的内存(堆),可以被main和func1函数使用
- func2中全局分配“abcdefg”(常量全局区)内存,可以被func1和main函数使用
四、栈的生长方向和内存存放方向
栈的生长方向
栈的生长方向:先后入栈二个变量a,b。如果b的内存地址确实比a小,说明栈的生长方向是由上往下的,即从高地址到低地址。
数组的生长方向:不管数组在栈区还是堆区,数组的生长方向都是从下往上的。也就是从低地址到高地址的。
比如数组: char buf[100]; buf[1]的内存地址肯定大于buf[0]的内存地址
#include <stdio.h>
int main(void)
{
int a;
int b;
printf("&a = %p, &b = %p\n", &a, &b);
int buf[100];
printf("buf: %p, buf+1:%p\n", buf, buf+1);
printf("\n");
return 0;
}
~
&a = 0x7ffc8ca55ac8, &b = 0x7ffc8ca55acc
buf: 0x7ffc8ca55ad0, buf+1:0x7ffc8ca55ad4