C语言_07 内存

 
前言: 程序的执行是放入内存中的,而我们在写代码时定义的变量, 函数等是存储在内存的不同区域. 不同的区域有着不同的特性.

参考资料和网上所说的内存分区大致可以分为两种: 分四个区和分五个区.

1.四区: 栈区, 堆区, 全局(静态)区, 常量(代码)区.
2.五区: 栈区, 堆区, 全局(静态)区, 常量区. 代码区.
其实这两者就是将最后一个区分为常量区和代码区.我们介绍的话就以五区来介绍吧. 主要将最后的那个区分开理解就好. 当然还有一种分四区: 栈区, 堆区, 数据区, 代码区. 将数据区细分为全局(静态)区, 常量区.虽然这样分很好理解,但是并不那么贴切(个人感觉). 来张图片理解一下(随便百度的): 最上面的计算机内核使用的归操作系统,虽然和我们编写程序没什么关系,但是也要了解以下.

内存五区:

1.栈区:

栈区,是我们最常用到的区域, 因为我们所有的普通局部变量全部存储在这个区.就如我们定义和使用局部变量一样. 在栈区的数据是不需要我们手动去申请和释放内存的. 这个过程全部由编译器帮我们完成,所以我们的局部变量可以直接使用.
int func(int x, int y){   //传递过来的参数 在栈区
    int z = x + y;     //函数内部定义的局部变量在栈区
    return z;
}

int main(){
    int a = 3;    //函数内部定义的局部变量在栈区
    a += 2;
    return 0;
}

2.堆区:

堆区,凡是手动malloc realloc calloc, 或者 C++中的new出来的变量都是存储在堆区. 如果学过数据结构或者用过C++的话就会知道, 数据结构中的链表是任意长度的,我们用c实现的话每个节点都是通过malloc函数创建出来的.而C++的话我们new出来的对象都是局部对象, 这些都是我们自己手动申请创建的内存.
注意: 我们手动申请的在堆区的时候,如果我们不手动释放(free)掉这段内存, 这段内存会一直占用直到程序结束. 手动释放掉内存后切记将该指针置空.
当然C++通过new 出来的对象系统会自动调用析构函数释放内存.
int *func(int x, int y){  //x y, 是在栈区

    int *p = malloc(4);  //p所指向的内存就存放在堆区.
    *p = x+y;
    return p;
}

int main(){
    int *p = NULL;
    p = func(3, 5);
    printf("%d\n", *p);
    free(p); //使用完后释放内存, 并将p置空
    p = NULL;
    //后续代码操作
    return 0;
}

3.全局(静态)区:

全局(静态)区:故名思义,全局变量和静态变量(static)存放的在这个区.这个区域也叫可读写区, 分为.data和.bss两部分,1 .data段(初始化全局|静态变量), 所有初始化了的全部变量存放的区域.则为数据分配空间,数据保存在目标文件中。2 .bss段(未初始化全局|静态变量), 所有未初化的全部变量存放的区域.不给该段的数据分配空间,只是记录数据所需空间的大小。 注意: 如果我们定义了一个全部整型变量并赋予了初始值0, 如果我们不给其赋值编译器也会在使用时赋予初始值0, 为了优化会将其放入.bss段, 当作未初始化处理.(看到有人的帖子这样说的,但是我不会验证 TAT!)附上帖子地址: http://blog.youkuaiyun.com/u010154760/article/details/46552303
int a;      //全局(静态)区
//int a = 0;  //据说都是在.bss段
int b = 2; //全局(静态)区,  .data段

void static fun_sta(){   //这个函数是存放在代码区的. 
}

void func(){
    static int a = 0;  //全局(静态)区.  额,这个应该也是在.bss吧.不知道有没有好心人告知一波...
    static int b = 1; //全局(静态)区.  .data段
}

int main(){
    static int a = 3;  //全局(静态)区 .data段
    return 0;
}

4.常量区:

常量区: (也叫文字常量区)我们在程序中使用的一些整型常量, 浮点型常量, 还有一个很容易误会的字符串常量都是存放在常量区.举个简单的例子: int a = 4; 我们知道a是存放在栈区的, &a的地址就是栈区的地址, 但是4却是存放在常量区.画图帮助理解. 普通的常量很好理解, 但是字符串有点特殊.举个例子.
int main(){
    char *s = "abc";   //字符串
    char *s1 = "abc";   //字符串
    char s2[] = "abc";  //字符串数组
    printf("%p\n", s);
    printf("%p\n", s1);
    printf("%p\n", s2);
    return 0;
}
输出结果:
panyiwen@god:~/temp$ ./a.out 
0x4006b4
0x4006b4
0x7ffe50893e90
可以看出指针s 和 s1指向的是同一个地址, 而s2和前两个都不同. 原因就是: s 和 s1 都是指向常量区的地址, 常量区只有一个字符串"abc", 而s2是一个普通的局部变量数组, 那么s2就是存储在栈区的一个字符串画图理解:

5 代码区:

代码区: 故名思义, 所有的代码是存放在这里.而且是编译后的二进制代码.当然这个区是由操作系统直接控制.
代码区和常量区因为都是不可修改的, 所以这两个区也被合并在一块称之为只读区.
再放入一张横向图片供参考.
鸣谢:
http://blog.youkuaiyun.com/czg13548930186/article/details/52766606
http://blog.youkuaiyun.com/androidxiaogang/article/details/50383516
http://blog.youkuaiyun.com/u010672206/article/details/46946593
希望能让你能有所收获, 不对的地方还请多多指教. 

查看原文: http://www.welcom212.com/wordpress/?p=326
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值