最近遇到的幾個純C程式設計的陷阱

2022-05-04 04:18:08 字數 2518 閱讀 1199

首先是乙個不容易看出來的語法上的陷阱

經過除錯得出的錯誤是對非socket的socket操作出錯,sockfd在除錯過程中發現是0,不是乙個合理的檔案描述符。

仔細一看原來是括號忘記加了,該運算是先用socket返回乙個檔案描述符fd,然後將fd<0的結果賦給sockfd,正常建立的socket的檔案描述符為正,所以fd<0的結果為0,c語言中0代表false,任何賦值運算都是true,所以也經常會出現寫掉乙個=導致條件表示式一直為true。比如if (ptr = null)。所以很多人推薦將右值寫在等號左邊來讓編譯器來檢查這種低階錯誤,比如if (null == ptr)。

這種寫法是《unix網路程式設計》上推薦的寫法,但是由於該書時間比較久遠,那時候用的還是c89標準,也就是所有變數必須先定義再使用。以前看過的很多書上vc6.0的mfc程式**就是這樣,迴圈變數也在函式開頭定義int i, j;(不過vc6本身對for迴圈就是不符合標準的= =b)

但是c99標準已經不必將所有變數在函式最開始就定義了,這種慣用法不一定值得大力提倡,畢竟括號多了容易看漏。

修改後

int sockfd = socket(af_inet, sock_stream, 0);

if (sockfd < 0)

清晰易懂。不過如果sockfd早就定義了,或者作為類的成員變數,之前那種2行合併的寫法更好。

下乙個問題,字元指標、字元陣列的問題

void printpermisson(struct stat* buf)

; if (s_isdir(buf->st_mode))

str[0] = 'd';

for (int i = 0; i < 9; i++)

write(stdout_fileno, str, 11);

}

首先是這麼寫出錯,因為雖然是char*,但是這種字面型字串(string literal)是分配在靜態區的(注意,"-rwxrwxrwx\n"是在靜態常量區,但是指標str是在棧上),這裡的char*和const char*無異,不能修改。

ok,於是改成了指標陣列char str[12]

當然,這裡我最初是寫成返回字串char*的,printf的工作留給函式使用者,即

char str[12] = "-rwxrwxrwx\n";

// ... 處理

return str;

這是很嚴重的錯誤,指標str和它指向的字元陣列內容"-rwxrwxrwx\n"都是在棧上,也就是說出了作用域後就會釋放記憶體,返回的指標指向一片不可用的記憶體!

所以這裡只有char* str = (char*)malloc(12);這麼動態分配記憶體,字元陣列內容是在堆上,需要使用者手動釋放。

然而,並不是「只有」這種手段,見我這篇部落格最後的錯誤更正linux和windows的遍歷目錄下所有檔案的方法對比

除了動態分配外,也可以把字串內容分配到靜態區(不是之前string literal分配的靜態常量區),它的宣告週期和全域性變數一樣,而不是出了作用域就銷毀,記得以前剛上c語言課時考試必考的一題就是這種,求func()函式執行幾次後的輸出

void func()

),而static變數則是一開始就存在,直到程式結束。

ps:c++11開始auto已經變成非常好用也非常容易濫用的語法糖了,自動型別推導。跟這個auto完全不一樣。

回正題,於是呢,利用static變數生存週期的特性,把之前返回字串char*的函式寫成這樣就沒問題了

static char str[12] = "-rwxrwxrwx\n";

// ... 處理

return str;

而readdir函式(見我之前提到的部落格)返回的struct dirent*則是類似這樣的手段來避免使用者來釋放記憶體(可惜也有像我這種自作聰明的人)

最後就記錄剛才除錯了很久的錯誤,感覺c真是寫得心累

程式是讀取linux下的空洞檔案(lseek或truncate等函式造成的,包含大量空白區域,即字元為\0,如果用普通的char buf[buffsize]來儲存,很有可能中途就因為strlen(buf)為0導致退出,於是我的思路就是用lstat計算出檔案大小size,用size / buffsize + 1作為迴圈次數。

但是卻輸出了這樣的東西。

原因是我沒有給buf初始化為0,然後每次讀寫的都是sizeof(buf)-1,為末尾留個結束符\0,但實際上字元陣列未初始化,最後一位的字元是隨機產生的(不為0)。

char buf[len];

printf("file size: %ld\n", statbuf.st_size);

for (int i = 0; i < statbuf.st_size / len; i++)

糾正方法就是char buf[len] = ;

唉,暫時說這麼多了,基本功還是很不紮實,當然也有c++寫習慣了的原因(構造/析構自動完成),實際寫**出現這些問題卻不能很快速地發現。

最近面試遇到的幾個題目

一。c net方面 1.怎樣防止進入admin資料夾。2.簡述下request a request.from a request.querystring a 作用和區別?3.列舉ado.net中的五個主要物件,並簡單描述?4.為什麼我們要使用泛型呢?或者 list 和arraylist 有什麼區別?...

最近遇到的幾個中文問題

1.filter編碼器在get方式請求的時候不會工作,要用filter來轉換編碼,就要用post,以後做專案考慮在tomcat中設定編碼,uriencoding gbk 注意tomcat的設定影響的是get請求,而filter影響的是post 2.ajax提交時非法字元的處理 提交 頁面的編碼是ut...

最近遇到的幾個python問題彙總

python中的版本是乙個很重要的東西,因為低版本向高版本幾乎完全不相容,高版本向低版本也幾乎是不相容的樣子。不知道python開發團隊在想什麼,哈哈。在網上查詢的第乙個方式如下 python c import matplotlib print matplotlib.version tracebac...