在正式開始今天的博文以前,先看一段代碼,思考這段代碼有可能出現的狀況:html
int main() { int j, b[10]; for(j = 1; j <= 10; ++j){ b[j] = 0; } }
看完這段代碼後,若是以爲這段代碼沒有什麼坑,那不妨注意一下j的範圍是從1-10,而b[10]會致使b數組越界哦。思考到結果了嗎?先來看看一些內存知識吧。ios
咱們在C/C++中學的變量分三種:局部變量、全局變量(靜態變量和全局變量)、堆變量程序員
局部變量 由程序員定義普通變量時編譯器在內存中的棧空間爲其分配一段內存,如:數組
int b[10], j;測試
全局變量 由編譯器在內存中的靜態存儲區分配空間,如:spa
int x, y; // 全局code
int main(){htm
static int m, n; // 靜態blog
}內存
堆變量 由程序員用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; }
原文出處:https://www.cnblogs.com/GuoYuying/p/11824495.html