從您可以原則 讀取和寫入任何地址,但它是唯一安全的和有意義的有組織,定義良好的方式訪問數據。
存儲器分配(顯式或隱式)的目的是將順序陷入混亂。當你聲明你的數組時,在棧上保留一小塊內存。
通常情況下,分配有一定的排列(有時有一定的最小尺寸,還需要操作系統只能檢測錯誤的訪問在一個非常粗糙的水平),所以往往會成爲你分配的內存塊和小區域之間小間隙是你可以寫和讀,似乎沒有任何「壞事」發生 - 但你應該假裝情況並非如此,你甚至不應該考慮使用這些實現細節來獲得優勢。
您的代碼示例「有效」,因爲您運行得不夠靈活而未命中未分配或寫保護的內存頁面,而且您沒有覆蓋導致應用程序崩潰的另一個重要堆棧值(例如函數退貨地址)。
我故意說「不幸」,而不是「幸運」,因爲它似乎工作的事實不是好事。這是不正確的代碼,並且這樣的代碼應該崩潰早,所以你可以檢測和解決問題。否則可能會導致很難診斷出現在完全不相關的時間或地點的問題。即使它現在起作用,你也不能保證它明天會工作(或者,在另一臺計算機上,或者使用不同的編譯器,或者代碼略有不同)。
內存分配通常是一個三步過程。這是一個分配請求操作系統C庫完成(通常並不直接對應您的要求),其次是一些簿記庫,和你作出承諾完成的。在操作系統級別,當您首次訪問內存時,頁面級別上的物理分配會按需進行,假設C庫先前已請求爲訪問的位置分配內存。
在堆棧分配的情況下,在庫級別上該過程稍微簡單一些,因爲它實際上只需要減少一個特殊寄存器,但這對於你來說大多是不相關的。這個概念保持不變。
您所做的承諾是,您只會讀取或寫入約定的區域,這對您而言是是重要的。
它可能發生,你違反你的承諾(故意或偶然),它仍然「有效」,但這純粹是巧合。
在堆棧上,你遲早會覆蓋一些局部變量的存儲(如果它們被緩存在寄存器中,它們可能未被檢測到),最後覆蓋返回地址,這幾乎肯定會導致崩潰(或類似的不受歡迎的行爲)時函數返回。在堆上,您可能會覆蓋一些其他程序數據或訪問未被傳送到操作系統的頁面作爲保留頁面。在這種情況下,該程序將立即終止。
讓我們暫時不考慮虛擬內存和頁面保護。
嚴格來說,不是
不正確代碼,而是調用未定義行爲的代碼。但是,覆蓋未分配的內存在我看來是足夠嚴重的,以便標籤「不正確」。
你租了一個5英尺深的容器中,然後你就卡住了8英尺長的箱子,破壞容器壁進入你的背後隱藏的另一個容器。幸運的是,另一個容器是空的,在你的情況下未使用。 – nos