在正式开始今天的博文以前,先看一段代码,思考这段代码有可能出现的状况:ios
int main() { int j, b[10]; for(j = 1; j <= 10; ++j){ b[j] = 0; } }
看完这段代码后,若是以为这段代码没有什么坑,那不妨注意一下j的范围是从1-10,而b[10]会致使b数组越界哦。思考到结果了吗?先来看看一些内存知识吧。程序员
咱们在C/C++中学的变量分三种:局部变量、全局变量(静态变量和全局变量)、堆变量数组
局部变量 由程序员定义普通变量时编译器在内存中的栈空间为其分配一段内存,如:测试
int b[10], j;spa
全局变量 由编译器在内存中的静态存储区分配空间,如:3d
int x, y; // 全局code
int main(){blog
static int m, n; // 静态内存
}编译器
堆变量 由程序员用malloc或new在堆上申请一段内存空间,如:
int *a = new int[10], *i = new int; // 动态内存分配
可见编译器经过将内存逻辑划分为不一样区段来提供程序员访问内存的权限,而每段空间都有各自的大小,一旦程序员在使用过程当中将该大小哦耗尽,就会出现内存不足错误,好比典型的Stack OverFlow
了解了变量的存储后,再来思考一个问题,当我在同一个变量区定义几个不一样变量时,他们在内存中是如何排列的?
好比我定义两个局部变量
int a,b;
那么究竟是编译器先为a分配地址,仍是先为b地址分配?(这还用思考吗?确定是先定义的先分配啦)分配地址后,究竟是a的地址高于b的地址,仍是b的地址高于a的地址?也就是下面这两张图哪张图是正确的?
想知道答案只须要将这两个的地址分别打印出来查看一下便可。这里小编就不打印了,建议读者自行打印。
打印结果是a的地址高于b的地址,也就是说左图正确。
可是注意这里的a,b均是局部变量,也就是变量存储在栈区,根据结果咱们发如今栈区定义的变量是先定义的变量分配在高地址区域,后定义的变量被分配在低地址区域(左图)。
那若是是堆区和静态存储区呢?
static int a, b;
int *a = new int, *b = new int;
本身动手打印一下地址吧。
结果发现,堆区和静态存储区与栈区刚好相反,堆区/静态存储区的变量,都是先定义的变量分配在低地址区域,后定义的变量分配在高地址区域(右图)。
总结来讲,就是局部变量高存低用,全局/静态/堆变量低存低用。
(高存(低存)描述的是多个变量同时定义时地址的占用方式是从高(低)地址往低(高)地址占)
(低用怎么理解:每一个变量在分配了内存单元后都是从该变量所占单元的低地址字节到高地址字节存放/读取数据)
如今返回来再看上面这段代码:
int j, b[10];
两个局部变量,还记得高存低用吗?本身动手画一下他们的内存分布图吧。
清楚了j 和 b数组的内存分配后,再来看这段代码(上图中a数组其实为b数组,画图的时候忘记改过来了)
int main() { int j, b[10]; for(j = 1; j <= 10; ++j){ b[j] = 0; } }
当 j 值为 10 时,b[10]会致使数组越界,而越界致使的结果就是b[10]会再继续往高地址占用一个int(4个字节)的存储空间,很明显,b[10]占用了 j 的地址,此时b[10] = 0 等价于 j = 0,会致使死循环。
(这里说的是理论结果,实际操做时 b 数组再越界1-2个内存单元才会占到 j 所在地址,实际操做只须要将 j <= 10的条件变为 j <= 11 或 j <= 12便可)
而若是将 j 和 b[10]的定义顺序交换一下:
int b[10], j;
就不会出现死循环哦,本身解释一下缘由吧。
这里咱们只讨论了局部变量的高存低用,别忘了还有全局/静态/堆变量的低存低用呢。
咱们将局部变量的 j 和 b[10]从新定义,从堆上申请内存,也就是
int *j = new int, *b = new int[10];
再遍历一遍,就不会出现死循环了哦
int main() { int *j = new int, *b = new int[10]; for(*j = 1; *j <= 10; ++*j){ b[*j] = 0; }
}
此时j, b都在堆上,且 j 相对 b 位于低地址处,不管 b 怎么越界都只会继续占用高址空间,占不到 j 的地址。(定义顺序换一下就死循环了哦)
下面附一下个人测试代码
#include <iostream> using namespace std; int x, y; int main() { cout << "Global variable:\n"; cout << "&x: " << &x << " &y: " << &y << endl; static int m, n; cout << "Static variable:\n"; cout << "&m: " << &m << " &n: " << &n << endl; cout << "Heap variable:\n"; int* a = new int[10], *i = new int; //int i, a[10]; for(*i = 1; *i <= 11; ++*i){ a[*i] = 0; } for(*i = 0; *i <=11; ++*i){ cout << "&a[" << *i << "]:" << &a[*i] << endl; } cout << "&i:" << i << endl; delete [] a; //delete i; //这里因为a的越界占到了i的空间,delete [] a其实已经将i占用的空间释放,这里再释放一次就会报错invaild pointer cout << "Stack variable:\n"; int b[10], j; for(j = 1; j <= 11; ++j){ b[j] = 0; } for(j = 0; j <=11; ++j){ cout << "&b[" << j << "]:" << &b[j] << endl; } cout << "&j:" << &j << endl; }