時間與空間複雜度之後還會繼續深刻,目前能夠先擱置一邊。linux
數據結構與算法中,最基本的兩個結構就是:數組、鏈表。兩者最大的區別在於:數組存儲地址是連續的,鏈表存儲地址不是(徹底)連續的。算法
數組能夠說的沒有多少,一是由於簡單;二是由於有不少文章都講的很詳細。因此咱們再也不贅述,本片對數組引出的兩個問題進行探討:windows
引用一張 linux 進程內存結構的圖,其中 stack 棧的生長方向是向下生長的,也就是向低地址生長,即好比從 0x10008 - 0x00010。windows的棧也是向下生長。而咱們都知道,數組的元素和其對應的地址是往大增加的:數組
好比:int a[2] = {0}
, 其中數組 a 的地址爲0x00010,那麼a[1] 的地址應該是 0x00010 + 1 * sizeof(int)
。數據結構
正是由於這種區別,考慮到以下的 C 程序 :佈局
#include <stdio.h>
int main() {
int i = 5;
int a[3] = {0};
int j = 6;
j = a[3]; // (1)
printf("j is : %d", j); // (2)
return 0;
}
複製代碼
運行後,輸出爲:ui
j is 5spa
爲何?操作系統
由於上述程序在執行 (1)以前,因爲(1)以前的變量都是局部變量,因此存儲在棧中。而上文說過了,棧的生長方向是向下的,且數組的元素地址是遞增的,因此(1)以前的內存(棧)佈局爲:翻譯
因此,當數組越界訪問 a[3]
時,就越界到了 i = 5
的位置,因此就會將 5 賦值給 j。
固然,實現上述結果的前提還有下面的兩點:
這個程序還能夠進行擴展,留到下次進行分析。
上面是數組如何存儲的,那麼數組中的某一個元素又是如何存儲的?好比 int i = 5
,其又是如何存儲的呢?
棧是一種數據結構,其本質是被操做系統管理的內存空間。變量 i 的存儲確定不是依靠操做系統來完成的,那麼是誰呢?
咱們寫好了某個語言的程序,程序須要轉換成機器語言即01010這種二進制語言纔可以被計算機識別,這一過程多是由編譯器來完成也多是由翻譯器來完成。
好比 i 轉換成機器語言後能夠用十六進制表示成 「0x00000005」(展開就是01010二進制),CPU須要讀取指令並執行,那麼當它收到這個數字時,又是如何解讀的呢?
假設 int 爲 4 字節大小,那麼一種解讀規則是:內存中的低位地址存儲 i 的高位字節,即:
0x00 | 0x1000 |
---|---|
... | ... |
0x05 | 0x1003 |
這種存儲模式就稱爲 大端存儲
而另一種模式則反過來,以下表:
0x05 | 0x1000 |
---|---|
... | ... |
0x00 | 0x1003 |
這種存儲模式就稱做爲 小端存儲
。
只有編譯器(解釋器)和 CPU 對於多字節數據的存儲模式相統一,纔可以正確執行程序。