今天朋友問我一道 C 語言的題目,如下圖:
看到這題一開始也比較納悶,arr[10] 不是越界了嗎?怎么會死循環?怎么 arr[10] 就是 m?這是什么意思?
我們先來看一個簡單的例子:
int i, a[10]; for(i = 1; i <= 10; i++) a[i] = 0;
這段代碼本意是要設置數組 a 中所有的元素為 0,卻產生了一個出人意料的 “副作用 ”。在 for 語句的比較部分本來是 i < 10,卻寫成了 i <= 10,因此實際上並不存在的 a[10] 被設置為 0,也就是內存中在數組 a 之后的一個字(word)的內存被設置為 0。如果用來編譯這段程序的編譯器按照內存地址遞減的方式來給變量分配內存,那么內存中數組 a 之后的一個字(word)實際上是分配給了整形變量 i。此時,本來循環計數器 i 的值為 10,循環體內將並不存在的 a[10] 設置為 0,實際上是將計數器 i 的值設置為 0,這就陷入了一個死循環。
上例摘抄自《C陷阱與缺陷》3.6節 邊界計算與不對稱邊界,畫了張圖更容易理解:
編譯器按照內存地址遞減的方式來分配內存,也就是先分配了 i 的地址,再分配數組a的地址,所以當循環計數器 i 的值為 10 時,其實指向的是 i 的地址,a[10] 就是 i,所以將 i 賦值為了0,進而這個例子將會產生死循環,不斷地給這個數組的每個數賦值為 0。相似的,我們開頭的那個題目也是一樣的原理。