數組越界訪問
⑴ 數組越界怎麼解決
1、什麼是數組訪問越界?
我們通過數組的下標來得到數組內指定索引的元素。這稱作對數組的訪問。
如果一個數組定義為有n個元素,那麼,對這n個元素(下標為0 到
n-1的元素)的訪問都合法,如果對這n個元素之外的訪問,就是非法的,稱為「越界。
數組佔用了一段連續的內存空間。然後,我們可以通過指定數組下標來訪問這塊內存里的不同位置。因此,當你的下標過大時,訪問到的內存,就不再是這個數組「份內」的內存。你訪問的,將是其它變數的內存了。
2、訪問越界會出現什麼結果?
首先,它並不會造成編譯錯誤!就是說,C,C++的編譯器並不判斷和指出你的代碼「訪問越界」了。一個明明是錯誤的東西,就這樣「順利」地通過了編譯。數組訪問越界在運行時,它的表現是不定的,有時似乎什麼事也沒有,程序一直運行(當然,某些錯誤結果已造成);有時,則是程序一下子崩潰。因此在使用數組時,一定要在編程中判斷是否越界以保證程序的正確性。
常見的錯誤就是數組的size值和下標訪問值弄錯,數組的下表是從0開始的,最大的訪問值是size-1。
3、解決辦法
由於數組的元素個數默認情況下是不作為實參內容傳入調用函數的,因此會帶來數組訪問越界的相關問題,解決問題方法,可以用傳遞數組元素個數的方法即:用兩個實參,一個是數組名,一個是數組的長度。
舉例:
#include<stdio.h>
void PutArray(int *p, int length)
{
// 在此判斷入口參數p和length的有效性
……
for(int
i=0;i<length;i++)
printf("%d\t",p[i]);
}
void main()
{
int a[3]={2,4,6} ;
printf("數組a[3]調用函數PutArray的結果為:\n");
PutArray(a,
sizeof(a)/sizeof(a[0]));
}
⑵ 為什麼數組越界會破壞數據
越界訪問有可能把數據放到已經存儲了重要數據的內存單元,也就是改寫了本來不許改寫的數據,如果這個數據是系統的重要內容,有可能導致系統運行紊亂甚至是崩潰。當然如果這個數據並不重要,那麼越界訪問的後果就不明顯或者是沒有影響。避免的辦法是對數組的下標嚴格監測,隨時注意下標是都越界。用指針訪問數組時隨時注意指針的指向是否已超過數組下邊的最大值。
⑶ 數組越界
任何的變數只是內存的一種表示而已,你定義了數組int a[2]表示你申請了4位元組連續的內存空間,a就代表其首地址,這片內存不會被別的程序使用,只有你的程序會使用它存取數據;a[4〕雖然沒有定義,但是這個內存空間是存在的,就是a+4,這片空間可能是被別的程序使用了,也可能是閑置著的,你不一定無權訪問,但是你如果訪問了很有可能會得不到你想要的結果,甚至會影響系統的運行,很有危險的!!
是啊!!
⑷ 數組越界訪問的危險性到底有多大
數組(指針)越界訪問,是指使用了超過有效范圍的偏移量。
如只分配了10個元素的空間,但是訪問了第11個元素,就屬於越界。
當出現越界時,由於無法得知被訪問空間存儲的內容及功能,所以會出現不可預知後果。可能程序崩潰,可能運算結果非預期,也可能完全沒有影響。
在編程時要避免指針越界訪問,對於用變數作為參數訪問元素時,需要控制好變數范圍。如果變數值由外部因素決定,那麼訪問前先對合法性做判斷,防止越界。
⑸ android數組越界問題 怎麼處理越界了
1、什麼是數組訪問越界?
我們通過數組的下標來得到數組內指定索引的元素。這稱作對數組的訪問。
如果一個數組定義為有n個元素,那麼,對這n個元素(下標為0 到
n-1的元素)的訪問都合法,如果對這n個元素之外的訪問,就是非法的,稱為「越界。
數組佔用了一段連續的內存空間。然後,我們可以通過指定數組下標來訪問這塊內存里的不同位置。因此,當你的下標過大時,訪問到的內存,就不再是這個數組「份內」的內存。你訪問的,將是其它變數的內存了。
⑹ 為什麼C語言檢查數組訪問越界會這么難
C語言中數組和內存管理,是安全性和性能之間矛盾關系的重要部分。
我曾提到要討論性能和安全性之間的矛盾。這個矛盾的一個重要部分就是因為C語言中數組和內存管理的本質特徵導致的。
理論上,數組是一個簡單的數據結構:當你需要訪問其中的一個元素時,只需要給出該元素的索引位置,就能對該元素進行讀或者寫操作。這句話中也隱含了
一個問題,那就是你需要訪問一個元素時,都需要提供一個索引位置。使用索引位置來找元素通常是一個代價很高的計算,尤其是當元素的大小不是2的整數次冪
時: 在諸如表達式++a[i], 在地址遞增的過程中,其計算地址的代價可以輕松超過5倍於a[i]的地址的代價。
在至少50年的時間里,編譯器開發人員一直在努力讓訪問數組元素變得更快。其中很大一部分的工作都圍繞想下面這種循環進行:
for (size_t i = 0; i < n; ++i)
c[i] = a[i] + b[i];
這段代碼在每次循環迭代中,都需要通過計算將三個索引地址轉換成對應的內存位置中,這種計算也帶入了一些開銷。 許多編譯器都通過將循環重寫為如下代碼的方式來實現高效計算。在這段代碼中,我們假設Pointer類型是可以指向a,b,c三個數組中某個元素的指針。
Pointer ap = &a[0], bp = &b[0], cp = &c[0], aend = ap + n;
while (ap < aend) {
*cp++ = *ap++ + *bp++;
}
這段轉換後的代碼將三個數組索引計算操作轉換成了三個地址加操作,這樣加速顯著。不過,這個簡單的轉換操作看起來容易,做起來卻很復雜,
因為編譯器需要能夠確認在這個for循環體中沒有對i值本身的修改。 上面的例子可以很直觀的看到i不會被改變,不過在實際的代碼中,往往要困難很多。
C語言與在它之前的編程語言相比,一個非常重要的不同就是C能提供給程序員一些直接優化代碼的機會,而不是簡單的依賴編譯器去做優化。C語言通過將數組和指針的概念統一化,使得程序員可以自己做大部分的數組索引計算,而在C語言之前,這些工作只能通過編譯器去做。
用手動計算索引取代自動計算是一種進步,這個聽起來有點怪怪的。但是在實際編程中,可能很多程序員都寧願手工優化代碼,而不是依賴編譯器自動優化,因為無法確定編譯器到底對代碼做了什麼。這也可能是吸引C程序員使用指針而不是索引來訪問數組元素的原因之一。
除了在很多情況下會更快外,指針相比數組還有另外一個很大的優勢:可以只用指向數組中特定元素的一個指針來識別數組中的元素。比如,假設我們想寫一
個函數來對數組中某個區域內的元素做操作。如果沒有指針,我們需要三個參數來確定這個區域:數組名稱,區域開始索引,區域結束索引。而如果使用指針的話,
只要兩個參數就足夠了。
此外,不管是動態分配的內存,還是其他內存地址,都可以統一使用指針。例如,在malloc庫函數返回一個指向動態內存的指針後,我們可以用這個指
針創建任何我們需要的數據結構。一旦我們在這塊動態分配的內存中創建了這些數據結構之後,我們就能使用指向這些數據結構某個部分的指針來讓其他函數可以直
接訪問這一部分數據。 相應的,這些函數也無需知道他們將使用的內存到底是什麼性質的。
使用指針是方便了很多,但是也要付出代價的。相比於使用索引變數引用數組元素的表示形式,使用指針的表示形式將會引入三種潛在危害。
第一,因為指向數組元素的指針和數組本身是完全獨立的。
因此,在數組不存在或者內存釋放之後,指針仍然有可能存在。比如,我們將數組元素的地址
&a[0]保存到指針ap中,我們同時也引入了在a不存在的時候,使用*ap的風險。這種風險在完全使用數組加索引的形式中是不存在的,因為一旦
數組a消失了,我們也無法引用他的元素。
第二,指針運算的可行性。
如果我們使用一對指針指向一個數組區間的兩端,那麼我們就一定能找到其中間元素的位置,因為可以直接使用數學運算得到。但
是這種指針的數學運算也同時引入了很多製造不可用地址的可能性,而且這種通過數學運算得到的不可用地址, 相比簡單的一些針對整數的數學運算來說,
更難檢測到。
最後,使用指針來表示範圍,不僅僅需要指針本身存在且可用,還需要指針指向的內存是可用的內存
。上面代碼中的aend變數就是一個典型例子。我們創
建了一個aend變數,並用它指向循環的上界。但是如果我們想試圖對*aend取值,結果將是未定義的。這類指針被稱為off-the-end指針。這類
指針的存在,也讓驗證C語言是否存在越界錯誤變得非常困難。
⑺ 數組越界操作是什麼原因
一、什麼是數組訪問越界? 我們通過數組的下標來得到數組內指定索引的元素。這稱作對數組的訪問。 如果一個數組定義為有n個元素,那麼,對這n個元素(下標為0 到 n-一的元素)的訪問都合法,如果對這n個元素之外的訪問,就是非法的,稱為「越界。 數組佔用了一段連續的內存空間。然後,我們可以通過指定數組下標來訪問這塊內存里的不同位置。因此,當你的下標過大時,訪問到的內存,就不再是這個數組「份內」的內存。你訪問的,將是其它變數的內存了。 二、訪問越界會出現什麼結果? 首先,它並不會造成編譯錯誤!就是說,C,C++的編譯器並不判斷和指出你的代碼「訪問越界」了。一個明明是錯誤的東西,就這樣「順利」地通過了編譯。數組訪問越界在運行時,它的表現是不定的,有時似乎什麼事也沒有,程序一直運行(當然,某些錯誤結果已造成);有時,則是程序一下子崩潰。因此在使用數組時,一定要在編程中判斷是否越界以保證程序的正確性。 常見的錯誤就是數組的size值和下標訪問值弄錯,數組的下表是從0開始的,最大的訪問值是size-一。 三、解決辦法 由於數組的元素個數默認情況下是不作為實參內容傳入調用函數的,因此會帶來數組訪問越界的相關問題,解決問題方法,可以用傳遞數組元素個數的方法即:用兩個實參,一個是數組名,一個是數組的長度。 舉例: #include void PutArray(int *p, int length) { // 在此判斷入口參數p和length的有效性 …… for(int i=0;i<length;i++) printf("%d\t",p[i]); } void main() { int a[三]={二,四,陸} ; printf("數組a[三]調用函數PutArray的結果為:\n"); PutArray(a, sizeof(a)/sizeof(a[0]));
⑻ C語言數組(指針)越界訪問
與編譯器無關,只與內存管理機制有關,是操作系統級別的問題,堆棧的讀取方式只是數據結構上的不同,在機器層面,依然是單純的內存讀寫操作;
數組越界訪問的危險性不好評估,但確實是最嚴重的危險之一;
結果基本上會100%崩潰,但是崩潰的原因很可能不一樣,就算是同一段越界代碼跑幾遍,原因也可能是不一樣的;
指針越界問題是不限於數組訪問的,所以全面點的解釋如下:
C語言的編譯時,會跟你的代碼需要,首先申請一塊棧空間和堆空間,棧的優先順序較高,一般時存放程序運行所必須的數據和變數,內存上是連續的,堆空間是程序運行時動態申請的空間,內存上一般是不連續的,這里說的棧與你自己創建的棧不是一個棧,不過數據結構是一樣的,只不過你自己創建的棧是靠你自己寫的代碼動態創建的,所以其實是在你程序的堆空間中的;
下面關鍵問題來了,
以上所有內存空間就是你的程序在跑起來之後,向操作系統申請的所有空間,換句話說,這些內存以外的數據,都是不屬於你這個程序的資源,當你使用指針操作的時候,如果你的指針越界了,那麼接下來你對這個指針的操作就是非法的了,如果這段空間依然是你程序內部的資源,通常會導致你程序自己崩潰,如果是程序之外的資源一般就更糟糕了,甚至會導致更高級別的崩潰,原因很多:
比如你篡改了不屬於你的數據,導致該數據所屬對象的邏輯混亂;
比如越界區域存在保護,內存空間是有讀寫許可權控制的,如果接下來你對只讀的空間進行寫操作,也會導致崩潰,windows下你會看到非常親切的藍屏;
等等...
這也是內存溢出攻擊的基本思想;