C语言内存四区的学习总结(一)---- 静态区

最近重新学习C语言相关知识,重新提到内存四区的概念,那么在之前的学习的基础上,在这儿做一个简单的总结与分享。

一、内存四区建立的流程

可以简单直观的查看下面的这个图片,直接的说明我们的程序在内存中是如何去存储,运行。。。。


程序运行的流程说明

1、操作系统把物理硬盘代码 load到内存

2、操作系统把c代码分成四个区

3、操作系统找到 main函数入口执行

二、各区元素分析

栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的等临时的值.

堆区(heap):一般由程序员分配释放(动态内存申请与释放),若程序员不释放,程序结束时可能由操作系统回收

全局区(静态区) (static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区城, 该区域在程序结束后由操作系统释放

常量区:字符串常量和其他常量的存储位置,程序结束后由操作系统释放

程序代码区:存放函教体的二进制代码

三、静态存储区和栈区的分析

就下面的程序做一个简单的分析:

#include "stdio.h"

char *getStr1()
{
    char *p1 = "abcd1";
    return p1;
}

char *getStr2()
{
    char *p2 = "abcd2";
    return p2;
}

char *getStr3()
{
    char *p3 = "abcd2";
    return p3;
}

int main(int argc, const char **argv)
{
    char *p1 = NULL;
    char *p2 = NULL;
    char *p3 = NULL;

    p1 = getStr1();
    p2 = getStr2();
    p3 = getStr3();

    printf("p1 = %s, p2 = %s, p3 = %s\r\n", p1, p2, p3);
    printf("p1 = %d, p2 = %d, p3 = %d\r\n", p1, p2, p3);

    return 0;
}

可以得出函数调用的模型为:


四、根据上面的程序开始逐步进行分析

在main开始执行之前,先进行假设栈区的开口向上,栈区中的横线形象的比方函数之间分割线,那么,在main开始执行的时候,

1、先定义了三个指针变量,分别是p1、p2、p3;那么此时在栈区会进栈三个变量,依次是p1 --> p2 --> p3;

2、调用函数getStr1,此时进栈p1;注意,此处的p1和main函数中的p1不是一个p1;

3、在常量区定义字符串”abcd1”,然后getStr1中的p1指针指向这个字符串(图中①,为黑色),假设字符串”abcd1”的首地址为0xaabb;

4、函数getStr1返回,将getStr1中的指针p1析构(图中用灰色表示,表示已经不存在了),所以①号线也随之断裂(灰色表示),将字符串”abcd1”的地址赋给main函数中的p1(图中②,地址用紫色表示)

5、调用函数getStr2,此时进栈p2,此处的p2和main函数中的p2不是一个p2

6、在常量区定义字符串”abcd2”,然后getStr2中的p2指针指向这个字符串(图中③,为橙色),假设字符串”abcd2”的首地址为0xbbcc;

7、函数getStr2返回,将getStr2中的指针p2析构(图中用浅橙色表示,表示已经不存在了),所以③号线也随之断裂(浅橙色表示),将字符串”abcd1”的地址赋给main函数中的p2(图中④,地址用橙色表示)

8、调用函数getStr3,此时进栈p3,此处的p3和main函数中的p3不是一个p3

9、此时本应该在常量区定义字符串” abcd2”,但是因为getStr3中的字符串和getStr2中的字符串是一样的,所以代码在编译的时候,编译器已经优化了并且只保留一个字符串”abcd2”,所以将getStr3中的p3指针指向这个字符串(图中⑤,为天蓝色)

10、函数getStr3返回,将getStr3中的指针p3析构(图中用浅天蓝色表示,表示已经不存在了),所以⑤号线也随之断裂(浅天蓝色表示),将字符串”abcd2”的地址赋给main函数中的p3(图中⑥,地址用橙色表示),此时,main函数中p2和p3实际上指向同一个内存

至此,getStrx(x=1,2,3)已经依次执行完毕,其中进栈的变量(p1,p2,p3均已经被析构),而main函数中的p1,p2,p3均从NULL指向属于自己的内存地址。


所以,在main函数中打印输出字符串的时候,可以看出效果为:


五、简单的总结

1、因为在程序运行过程中,系统将代码区代码load到内存中,所以,代码区透明的,此后不需要关注

2、指针指向谁,就将谁的地址赋给指针:char *p1 = “abcd1”;

3、指针变量和他指向的内存空间变量是两个不同的概念p1,”abcd1”

4、不同的局部变量(不同函数中)的常量(比如字符串常量“abcd2”),如果常量相同的话编译器会进行优化,讲这些一样的常量划分到一个全局区的某个地址中,只不过用参数的形式可以通过函数调用对此参数进行初始化。

 

posted @ 2019-04-04 09:55  我就叫宋帅呀  阅读(242)  评论(0编辑  收藏  举报