两个基本概念
数据类型:一段不同大小、连续的内存空间
变量:一段连续的内存空间的别名
int a; //申请4个字节的连续空间存储数据
char *p; //申请4个字节的连续空间存储数据
为什么要这样解释呢,这有助于我们更加了解程序的执行,站在编译器的角度去思考代码。毕竟代码是写给人看的,却是用编译器来编译的,有时写代码的时候,站在编译的角度去思考,可以避免很多错误。要知道没有无缘无故的代码!至于教科书上写的 int、char、double、float、long、long long、其实只需记得他们代表着不同大小、连续的内存空间,内存空间大小不同就意味着取值范围不同。理解这个,可以抵上教科书上的50页的内容了。不过话说回来,不看书不写代码也不会有深的体会!
空间出自于哪里,往哪里去 ----内存四区
1.堆区:平常我们又称malloc区。系统为提供了一系列的API操作这份空间。当然也有很多其他的库对malloc进行了封装,例如有zmalloc,jmalloc等。像redis缓存数据库用的便是zmalloc。malloc区要手动申请,手动释放,平常这是一个考验程序员的地方。申请的空间没有释放,会有内存泄漏,释放的空间不小心再次访问会出现结果异常,甚至程序奔溃!
2.栈区:编译器自动分配释放,在编译的时候,就给它预留了一定空间的内存。局部变量便是在栈区。
3.全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放、常量区就是 常量字符串就是放在这里的。 程序结束后由系统释放。
4.代码区,存储函数体的二进制代码。
#include
#include
#include
int g_val = 1; //在全局区
static s_val; //静态存储区
void * test(){
char *p = NULL;
p = (char*)malloc(sizeof(char)*100); //可以装换为任意类型 申请的内存在堆区但是变量p是在栈区
if(!p){
printf("malloc failed\n");
return NULL;
}
return p;
}
int main(){
const char *c = "nihaoymw"; //c指向全局常量区,即"nihaoymw"在全局常量区,这里要加上const,不允许修改
int a = 4; //a的对应的内存空间在栈区
int b = 5; //b的对应的内存空间在栈区
char *q = test(); //这里有局经典的话语,指针指向谁,就把谁的地址赋予它
if(!q) free(q);
return 0;
}
//以上代码纯文本写,权当参考!
可以说理解内存四区,至关重要,平常写代码出现很多莫名其妙的问题,很大程度是出自于这里!这也是面试的时候面试官很喜欢问的一个问题,因为它太重要!这里可能会涉及到栈和堆的生长方向,证明也比较简单,这里不做记录!
函数调用模型
对于函数的执行始终记住一句话:先执行的函数最后结束!
变量三要素是:名称、大小、作用域。其中作用域和函数的执行情况息息相关。总结有三点:
1、主调函数分配的内存空间(堆,栈,全局区)可以在被调用函数中使用,可以以指针作函数参数的形式来使用。
2、被调用函数分配的内存空间只有堆区和全局区可以在主调函数中使用(返回值和函数参数),而栈区却不行,因为栈区函数体运行完之后,这个函数占用的内存编译器自动帮你释放了。
3、一定要明白函数的主被调关系以及主被调函数内存分配回收(这三句是借助前辈们的金言)。