數組(Array)是一種線性表數據結構。它用一組連續的內存空間,來存儲一組具備相同類型的數據。算法
咱們拿一個長度爲10的int類型的數組 int[]a=new int[10] 來舉例。數組
在我畫的這個圖中,計算機給數組a[10],分配了一塊連續內存空間1000~1039,其中內存塊的首地址爲base_address = 1000網絡
計算機會給每一個內存單元分配一個地址,計算機經過地址來訪問內存中的數據。當計算機須要隨機訪問數組中的某個元素時,它會首先經過下面的尋址公式,計算出該元素存儲的內存地址:數據結構
ss = base_address + i * data_type_size
其中data_type_size表示數組中每一個元素的大小。(int類型的大小爲4個字節)框架
跟插入數據相似,若是咱們要刪除第k個位置的數據,爲了內存的連續性,也須要搬移數據,否則中間就會出現空洞,內存就不連續了。數據結構和算法
實際上,在某些特殊場景下,咱們並不必定非得追求數組中數據的連續性。若是咱們將屢次刪除操做集中在一塊兒執行,刪除的效率是否是會提升不少。性能
例如,數組a[10]中存儲了8個元素:a,b,c,d,e,f,g,h。如今,咱們要依次刪除a,b,c三個元素。爲了不d,e,f,g,h這幾個數據會被搬移3次,咱們能夠先記錄下已經刪除的數據。每次的刪除操做並非真正搬移數據,只是記錄數據已經被刪除了。當數組沒有更多的空間存儲數據時,這樣就大大減小了刪除操做致使的數據搬移。學習
若是你瞭解JVM,你會發現,這不就是JVM標記清除垃圾回收算法的核心思想嗎?沒錯,數據結構和算法的魅力就在於此,不少時候咱們並非要去死記硬背某個數據結構或者算法,而是要學習他背後的思想和處理技巧,這些東西纔是最有價值的。優化
首先分析一下這段C語言代碼的運行結果:spa
int main(int argc, char* argv[]){ int i = 0; int arr[3] = {0}; for(; i<=3; i++){ arr[i] = 0; printf("hello world\n"); } return 0; }
你發現問題了嗎?這段代碼的運行結果並不是打印三行「hello world」,而是會無限打印「hello world」。
由於,數組大小爲3,a[0],a[1],a[2],而咱們的代碼由於書寫錯誤,致使for循環的結束條件錯寫爲了i<=3而非i<3,因此當i=3時,數組a[3]訪問越界。
咱們知道,在C語言中,只要不是訪問受限的內存,全部的內存都是能夠自由訪問的。根據咱們前面講的數組尋址公式,a[3]也會被定位到某塊不屬於數組的內存地址上,而這個地址正好是存儲變量i的內存地址,那麼a[3]=0就至關於i=0,因此就會致使代碼無限循環。
數組越界在C語言中是一種未決行爲,並無規定數組訪問越界時編譯器應該如何處理。由於,訪問數組的本質就是訪問一段連續內存,只要數組經過偏移量計算獲得的內存地址可用,那麼程序就可能不會報任何錯誤。
這種狀況下,通常都會出現莫名其妙的邏輯錯誤,就像咱們剛剛舉的例子,debug的難度很是大。並且,不少計算機病毒也正是利用了代碼中的數組越界能夠訪問非法地址的漏洞,來攻擊系統,因此寫代碼的時候必定要警戒數組越界。
對於業務開發,直接使用容器就足夠了,省時省力。畢竟損耗一丟丟性能,徹底不會影響到系統總體的性能。但若是你是作一些很是底層的開發,好比開發網絡框架,性能的優化須要作到極致,這個時候數組就會優於容器,成爲首選。