C語言:陷阱與缺陷詳解
一、前言
二、字符指針
結論一:復制指針並不會復制指針所指向的內容。兩個指針所指向位置相同,實際為同一個指針。
結論而:開辟兩個數組,即使兩個數組內容相同,地址也絕不相同。
三、邊界計算與不對稱邊界
1.經典錯誤①
int main() { int i = 0; int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; for (i = 0; i < 13; i++) { arr[i] = 0; printf("haha"); } return 0; }
計算的結果是程序陷入死循環
分析:
1.棧區默認先使用高地址,再使用低地址
2.數組內元素隨下標增長,地址由低到高變化
調試後即可發現,i與arr[9]的地址相差3字節,所以i即為實際不存在的arr[12].
[補充知識:ANSI c標準允許這種用法——數組中溢界元素的地址位於數組所占內存之後,這個地址可以進行賦值和比較,但是不能解引用(若是數組之前存在溢界則語法不允許)]
2.經典錯誤②
十米長的圍欄每一米就需要一根欄桿支撐,則共需要幾根欄桿? 11
3、小結
欄桿問題你若不假思索可能會回答為10。欄桿問題的根源正是加減一帶來的困惑
對此我們堅持以下原則
原則一:考慮最簡單的特例(如考慮20到10間有幾個數,20-10還要+1嗎。不妨考慮10到10有幾個數)
原則二:仔細計算邊界
而在實際編程中,一個編程技巧則可以”一言以蔽之”,即不對稱邊界。
x>=0 && x<16 要優於 x>=0 && x<=15
不對稱邊界上界-下界就是之間所包含的數。
四、求值順序
總結:c語言中隻有四個運算符(&& ;|| ;?: ;,)明確規定瞭求值順序
&&和||先對左邊求值,隻在需要時對右邊求值:
if(y!=0 && x/y>a)
如此避免除0錯誤。
特別註意,賦值操作符不保證任何求值順序,即使考慮瞭優先級和結合性,也會有意想不到的錯誤
int i=0; while(i<n) { y[i]=x[i++] }
對於以上的代碼,就不能確定y是否在i自增之前求值。
問題代碼1:c+–c(我們可以根據”大嘴法”判斷為c+(–c)),但c自增的先後不得而知)
問題代碼2:int a=(++i)+(++i)+(++i) (同理)
問題代碼3:answer=func()-func()*func() (我們不知道哪個func被先調用)
五、運算符&& ||和!
這三種運算符返回值都為0或1。在結果為真是返回1,結果為假是返回0。
考慮一下代碼,其功能是查詢表中一個特定元素
int i = 0; while (i < tabsize && tab[i] != x) { i++; }
現分析將&&替換成&仍然能”正常工作”的原因。
原因一:隻要xy的值都限制在0~1,x&&y和x&y的結果始終相同。
原因二:數組結尾之後的下一個元素,隻要不改變他的值而僅僅是讀取,沒有什麼大的危害
原因三:不同與&&的求值順序,&要求兩邊都要被求值
如果tabsize大小等於tab中元素的個數,即使i=tabsize後還會繼續查找下去,陷入死循環
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!