c的某些語法容易讓人不小心觸雷,比如
從0開始的下標
很多高階語言中,定義n個元素的陣列,下標範圍是從1到n,但c特殊,n元素的c陣列中沒有下標為n的元素,只有從0到n-1的下標。所以使用c陣列時不要犯這種錯誤:
int i, a[10];
for ( i = 1; i <= 10 ; i++ ) //i=10時超出陣列邊界
八進位制or十進位制常數
c編譯器會把數字025當作八進位制,等於十進位制的21,因此在使用常整數時不要認為多個0無關緊要,特別在從其他檔案或標準中拷貝一些常係數陣列時,要留意預防。
未初始化變數
變數未初始化往往帶來很難查詢的隨機錯誤,下面是開發中真實的例子:
typedef struct tag_parmparm;
/*結構體初始化*/
parm spliterparm;
spliterparm.clip = &ifilename;
spliterparm.initparsingenable = iparsingmode;
/*呼叫*/
res = open(&spliterparm);
ishttpstream是後期新增的乙個成員變數,初始化部分忘記給它賦值,而在open函式裡有:
這就導致open隨機執行到不同分支。變數未初始化的主要表現就是多次執行同樣程式,隨機錯誤。未初始化的問題很常見,特別是結構體,其定義和初始化不象普通區域性變數那樣相距很近,所以標頭檔案裡成員變數改變後很容易遺漏對應的初始化。
浮點數比較和交換
void main()
else }
結果是error。浮點數是為了能用二進位制表達小數而引入的一種量化形式,轉換時存在捨入誤差,因此不能直接用==比較浮點數。正確做法是確定乙個誤差範圍,通過比較兩浮點數差值是否落在這個誤差範圍內來判定是否相等,即:
const float delta = 0.1
void main()
else }
同樣,由於浮點數有捨入誤差,也不滿足交換定律,如浮點數float x=1/3,y=1/6,z=1/7;
和整數不同,x*y/z不等於x*(y/z)。
字串結尾的隱含結束符導致記憶體越界
char *r = malloc(strlen(s) + strlen(t));
strcpy(r, s);
strcat(r, t);
以上實現忘記了字串結尾隱含的空字元,strlen()返回字串裡真正的字元數,但不包括結尾的空字元。因此如果strlen(s)是n,則s需要n+1個位元組空間儲存。即:
char *r = malloc(strlen(s) + strlen(t) + 1);
strcpy(r, s);
strcat(r, t);
log語句中的有效操作
有人認為printf/log/trace等列印函式的唯一功能就是輸出調式資訊,因而隨意對待它們,但是printf等函式裡也能包含有效操作,如:
int a[5]=;
int *ptr = a;
printf(「%d」, *(++ptr));
*(ptr++) += 123;
單純把printf看做log語句,修改程式時就可能隨手注釋掉(printf開開關關經常發生),而printf內的有效操作也同時被刪除,類似情形還包括printf內的函式呼叫等。因此最好把printf和有效操作放在兩條語句,否則是自己挖坑。
C陷阱篇之常見手誤
c的某些語法容易讓人不小心觸雷 很多高階語言中,定義n個元素的陣列,下標範圍是從1到n,但c特殊,n元素的c陣列中沒有下標為n的元素,只有從0到n 1的下標。所以使用c陣列時不要犯這種錯誤 int i,a 10 for i 1 i 10 i i 10時超出陣列邊界 八進位制or十進位制常數 c編譯器...
C 常見陷阱之 語法
至少在2018的今天,c 的函式引數求值順序仍然是未定的 交給編譯器處理 所以函式引數求值的順序可能在某些情況下回導致一些問題。看下面這個例子 int test 5 printf d,d,d n test,test,test test 5 printf d,d,d n test test,test ...
C 常見陷阱
注 char型別在標準中是個特別的存在,它沒有被規定為有符號或無符號。比如int指的是有符號,而char不一樣。在程式設計時最好給char寫上符號,否則同樣的表示式可能在不同的編譯器 平台會有不同的結果。請觀察乙個程式輸出 int main 輸出 fffffff1,fffffff2,f0f2 fff...