1. 程式人生 > >陣列越界問題、指標初入門

陣列越界問題、指標初入門

主要內容:陣列越界問題和指標初入門例子分析

一、 陣列越界問題

  1. 例子思考
int main()
{
	int i;
	int arr[10];
	for(i=0;i<=10;i++)
	{
              arr[i] = 0;
	          printf("%d\n",i);
	}
	return 0;
}

問題:當執行上述程式碼時,會出現什麼問題?為什麼會這樣?

 為解決以上問題,我們首先得明白當定義一個函式時,函式中各個量的空間分配符合棧(後進先出)的原則,如果一個量被先定義,那麼系統便先給它分配儲存空間。而在陣列中,0號下標地址值永遠小於1號下標地址值。因此,對於上述問題,我們可以畫出它的記憶體空間示意圖,分析執行程式碼會出現什麼結果。具體圖如下所示:


 根據上圖所示,程式從主函式開始往下執行,當int i;時,系統首先為i分配四個位元組的空間,接著int arr[10];時,定義了一個長度為10的陣列,因為在陣列中,0號下標地址值永遠小於1號下標地址值,同時棧的定義就是棧底地址大。便可知到上圖(左)(圖中兩紅線之間表示為陣列所佔空間)便為定義後,i與陣列arr在記憶體中分配圖。接著執行:for(i=0;i<=10;i++){arr[i] = 0; printf("%d\n",i);}。當i<10時,陣列下標0-9分別對應的元素被賦值為0。i=10時陣列滿溢,會發生越界情況。在陣列越界情況中,陣列會預設牽涉其鄰近元素,在此例子中即為i,因此當i=10

時,系統會將i所對應的值賦為0。

  1. 結論
     此段程式碼執行時會產生死迴圈。原因是:因為陣列越界,當i=10時,系統將i所對應的值賦為0,此時i=0i<=10系統又會進入新一輪迴圈。以此類推,系統陷入死迴圈。

  2. 解決辦法
     i.編譯器:Visual Studio 2012針對於上述問題會產生崩潰現象,具體實現過程如上圖(右),VS12會在陣列arr與變數i中間進行隔離,避免陣列越界影響到i,同時在陣列arr與變數i中間申請兩個記憶體空間,分別放在兩顆“炸彈”,陣列一旦越界,觸碰到炸彈,系統中斷,提出警告。
     ii.人力控制:牢記陣列最大下標值=陣列長度-1,程式碼仔細書寫,避免越界問題產生。

二、 指標初入門

  1. 概念介紹
    符號& :表示取地址。//eg: &a表示取a 的地址。
    符號* :可以表示乘法、定義一個指標變數、對變數解引用。//eg: 34、intp(定義一個指標變數p)、*p(對p解引用)
     首先我們得知道指標==地址 ,通過以下介紹,我們來理解指標為什麼相當於地址。
    在這裡插入圖片描述

  2. 例子思考
    其中&a=1000,&b=2000,&p=3000,觀察此程式碼,分析每一步都做了什麼!

int main()
{
	int a = 10;
	int b = 20;
	int *p = &a;
	*p = 100;  
	p = &b;                     
	*p = 200;                       
	int **pp = &p;
	*pp = &a;                  
	**pp = 1000;                
	*pp = &b;                       
	**pp = 2000;               

	return 0;
}

 對上段程式碼,我們畫圖理解:在這裡插入圖片描述

 (1)定義一個整形變數a,並將10賦值給它;
 (2)定義一個整形變數b,並將20賦值給它;
 (3)定義一個整形指標變數p儲存變數a的地址,此時執行上圖中的第(1) 步,p指向a;
 (4)*p = 100;對p解一次引用,此時p指向a,即a=100;
 (5)指標變數p儲存變數b的地址,此時執行上圖中的第(2) 步,p指向b;
 (6)*p = 200;對p解一次引用,此時p指向b,即b=200;
 (7)定義一個整形二級指標變數pp儲存指標變數p的地址;
 (8)對pp解一次引用,也就是執行上圖中的第(3) 步,pp指向p,此時p中儲存的是a的地址,即p=&a;
 (9)對pp解兩次引用,也就是執行上圖中的第(3) 步,再執行第(1) 步,pp指向p,此時pp指向a的值, **pp = 1000,也就是將a的值置為1000;
 (10)對pp解一次引用,也就是執行上圖中的第(3) 步,pp指向p,此時將b的地址賦值給p,p中儲存的是b的地址,即p=&b;
 (11)對pp解兩次引用,也就是執行上圖中的第(3) 步,再執行第(2) 步,pp指向p,此時pp指向b的值, **pp = 2000,也就是將b的值置為2000;
因此,此程式碼每一步都做了什麼展示如下:

int main()
{
	int a = 10;(1)
	int b = 20;(2)
	int *p = &a;(3)
	*p = 100;(4)                             //a = 100;
	p = &b;(5)
	*p = 200;(6)                             //b = 200;
	int **pp = &p;(7)
	*pp = &a; (8)                            //p = &a;
	**pp = 1000; (9)                         //a = 1000;
	*pp = &b;(10)                             //p = &b;
	**pp = 2000;(11)                         //b = 2000;

	return 0;
}