[C語言]這些bug,你遇到過嗎,持續更新中……

1、釋放動態內存時遇到“user breakpoint called from code at 0x********”

這個bug多在調用free函數來釋放malloc的內存時出現,前先曾多次遇到,但一直未找出問題原因。

在網上查了一下,有些寫得挺複雜,涉及到了操作系統推維護的內容,現在還不有接觸 到這一塊,所以沒有細看。其他有說到重複釋放動態內存,修改動態內存指針或者破壞了系統的動態內存結束標誌都會導致這個bug。後來查看自己的代碼,發現 重複釋放的問題倒是沒有,卻在操作內存時有一處頻繁操作超出動態申請內存之外的單元,故導致這個問題的出現。

問題總結:在動態內存釋放時出現,多由於動態內存使用不當
1、重複釋放動態內存,調用free後應立即將指針賦NULL,最好寫個宏將free和指針賦NULL包含進去,以免遺漏;
2、讀寫操作超出了動態申請內存邊界(讀應該不會發生問題,但也要避免,除非你真正明白自己在幹什麼)

2、C中的字符串異常

嚴格地說,C中是沒有字符串變量的,一般採用字符數組或字符指針的方式才實現字符串的操作,二者在使用中有諸多類似,但並不是完全等價的,注意下面兩句的區別:

char a[] ="Hello world";//存放在棧中,可以修改a數據組的任意值  
char*s ="Hello world";//指針s存放在棧中,字符串常量在代碼段,不可修改

 

給s[i]賦值將導致錯誤

更正:經測試,在VC 6.0環境下
指針指向常量字符串時,在Debug模式下會出現程序崩潰,而在Release模式下則不會,且字符串被保存在數據段,而不是代碼段
另外在TC 2.0下也不會出現該問題
但還是儘量使用char p[]="**"的形式來定義字符串

因爲在Release下,編譯器會進行一些優化,如下

char*p1 ="ABC";
char*p2 ="ABC";

*p1 ='D';
puts(p1);
puts(p2);

  p1和p2指向的是同一塊內存地址,修改p1指向的內容會導致p2的內容改變,這是不符合期望的。而在Debug模式下雖不進行如此優化,但會使程序會崩潰。

3、條件判斷時一定要學會利用短路特性來防止異常,如
 

while(j >=0&& a[j] >0) j--;  
if(d !=0&& n/d ==0)
if(p == NULL ||*p =='\0')/*no string*/

例中3種情況漏掉前一個條件或將兩個判斷條件調換了次序都會導致內存溢出。

4、關於混亂的類型擴展問題

因爲不確定編譯器採用哪種保護規則(無符號保護或是值保護),應儘量避免在同一個表達式內混用有符號和無符號的變量。任何時候,總可以用顯式的類型轉換來明確無誤地表達所希望的轉換的地方或方式。

5、類型轉換被當成左值

在C語言中,類型轉換操作只能生成一個右值,不能被賦值或進行自增(減)運算。

char*p;  
((
int*)p)++;

不能完成預想中的將p增加一個int的長度,而應該如下:

p= (char*)((int*)p +1);

或p
+=sizeof(int);

 

6、變長參數函數調用中,會進行默認類型轉換嗎?

下面這段代碼的輸出是什麼?

#include <stdio.h>  

int main()
{
__int64 n;
int b;

n
=1;
b
=2;
printf(
"%d,%d\n",n,b);
return0;
}

 

和預料不同的是,它輸出:1,0

這是因爲在可變參數函數調用中,一般編譯器是不進行默認的類型轉換的,當函數根據格式字符串從棧中提取參數時就會由於變量長度不一致而產生異常的輸出。在上例中,printf函數首先根據%d從棧中提取一個int將其輸出(n的低32位內容),然後將指針下移一個int的長度,再取(此時取的正是n的高32位內容)一個int輸出。

但應注意像printf這樣的函數有“默認參數提升”規則,即char和short總是被提升爲int,float總是被提升爲double。所以printf只能用“%f”輸出double,而scanf必須用"%lf”來接受一個double型數據的輸入。

7、返回局部變量的地址(或引用:C++)

不要對局部變量進行地址返回和引用返回,即使你設想相應的地址空間十之八九還保持原值。局部變量被放在程序的堆棧空間,函數返回後,其棧空間即被釋放,相當於失去了保護,相應的棧空間可能馬上會被破壞掉,比如說進行另一函數調用。

即使立即將數據轉存也不是百分之百的安全(VC 6.0下測試發現:debug模式下執行行checkesp會存壞一部分,release下可能局部變量直接被優化掉了,根本沒有直正存入內存),所以,最保險的辦法就是永遠不要這樣幹!!

 

8、將char類型提升到unsigned

char c = 0xff;

unsigned d = (unsigned)c;

  d = ?

答案是:0xffffffff;而不是我預想中的0xff;

char向unsigned提升的過程可以認爲是:(char) -> (int) -> (unsigned int)。比如下面的代碼就隱藏了一個很重大的bug

unsigned int offset;
char *pChar

offset = (unsigned int)(*(pChar-1));
offset |= (unsigned int)(*(pChar-2)) << 8;
offset |= (unsigned int)(*(pChar-3)) << 16;
offset |= (unsigned int)(*(pChar-4)) << 24;

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章