有了之前的基礎(chǔ),此文只是把一些以前沒有注意到的和值得學(xué)習(xí)的知識做一個記錄。
第一章
作者認(rèn)為使用#if 0 .... #endif比用/*和*/好,因為后者不能嵌套。但是對于//并沒有說明。
第二章
三字母詞,用兩個問號加一個符號表示另一個符號,比較類似于轉(zhuǎn)義字符。查閱了一些資料,它的使用與編譯器有關(guān),了解即可,防止字符串常量被錯誤的解釋。
??) ==> ] ??> ==> } ??/ ==> /
??! ==> | ??' ==> ^ ??- ==> ~
第三章 數(shù)據(jù)
對于static的復(fù)雜用法,當(dāng)它用于函數(shù)定義或代碼塊之外的變量聲明時,static用于修改標(biāo)識符的連接屬性,從external改為internal,但標(biāo)識符的存儲類型和作用域不受影響。用這種方式聲明的函數(shù)或變量只能在聲明它們的源文件中訪問。當(dāng)它用于代碼塊內(nèi)部的變量聲明時,static用于修改變量的存儲類型,從自動變量修改為靜態(tài)變量,但變量的鏈接屬性和作用域不受影響。用這種方式聲明的變量在程序執(zhí)行之前創(chuàng)建,并在程序的整個執(zhí)行期間一直存在,而不是每次在代碼塊開始執(zhí)行時創(chuàng)建,在代碼塊執(zhí)行完畢后銷毀。
第五章 操作符和表達(dá)式
移位操作,當(dāng)移動的位數(shù)為負(fù)值時,具體的結(jié)果與編譯器有關(guān)或者是未定義的,比如a<<-5可能是左移27位。
形如a+=1的操作效率比a=a+1高,等價的a[ 2 * (y - 6*f(x)) ]=a[ 2 * (y- 6*f(x))] + 1與a[ 2 * (y- 6*f(x))] += 1相比,后者不用重復(fù)計算下標(biāo)。
sizeof x的形式是允許的。sizeof()并不對表達(dá)式求值,因此sizeof(a=b+1)中的a沒有賦值。
訪問指向結(jié)構(gòu)的指針的成員時只用->。
第六章 指針
未初始化的指針會導(dǎo)致錯誤。int *a; *a = 12,這使a指向的地址的內(nèi)容被修改,結(jié)果是無法預(yù)料的。
作者認(rèn)為在諸如搜索元素而未找到時返回值為NULL指針雖然是C的常用技巧,但違背了軟件工程的原則:“用一個單一的值表示兩種不同的意思是件危險的事,因為將來很容易無法弄清哪個才是它的真正用意”。安全的策略是返回兩個值,表示是否成功的狀態(tài)值和查找成功時所查找到的元素值。
第七章 函數(shù)
無參數(shù)的函數(shù)原型聲明應(yīng)該寫作這樣:int func(void); 目的是不與舊式風(fēng)格聲明混淆。
遞歸解決問題比非遞歸更為清晰,對于一個復(fù)雜問題,難以用迭代形式實現(xiàn)時,遞歸實現(xiàn)的簡潔性可以補償它所帶來的開銷。Fibonacci是一個常見的遞歸的例子,但冗余計算很多,開銷太大,實際上并不如迭代實現(xiàn)。
long fibonacci(int n)
{
long result;
long previous_result;
long next_older_result;
result = previous_result = 1;
while( n > 2) {
n -= 1;
next_older_result = previous_result;
previous_result = result;
result = previous_result + next_older_result;
}
return result;
}
float average( int n_values, ... )
{
va_list var_arg;
int count;
float sum = 0;
/*準(zhǔn)備訪問可變參數(shù)*/
va_start( var_arg, n_values) ;
/*添加取自可變參數(shù)列表的值*/
for (count = 0; count < n_values; count += 1) {
sum += va_arg( var_arg, int);
}
/*完成處理可變參數(shù)*/
va_end(var_arg);
return sum/n_values;
}
第八章 數(shù)組
int array[10];int *ap =array+2;在這之后,ap[0]在C里是合法的,它等同于array[2],ap[-1]同樣是合法的,即array[1]。
指針比數(shù)組更有效率的場合:for循環(huán)的ap++比循環(huán)體中的array[a] = 0有效率,前者的乘法計算只有一次,用于1與數(shù)據(jù)類型長度相乘,而后者每次都需要進(jìn)行計算。
/* 使用指針 */
int array[10], *ap;
for ( ap = array ; ap< array + 10; ap ++ )
*ap = 0;
使用指針訪問多維數(shù)組的方法,例如對于數(shù)組int matrix[3][10],聲明int *mp = matrix是錯誤的,因為matrix并非一個指向整型的指針,而是一個指向整型數(shù)組的指針。int (*p)[10] = matrix是可以的,p指向matrix第一行,實現(xiàn)對數(shù)組的逐行訪問。如果需要逐個訪問,則使用int *pi = &matrix[0][0]或int *pi = matrix[0],使它指向第一個元素。而 int (*p)[] = matrix;是不正確的,它的值根據(jù)空數(shù)組的長度調(diào)整,這一錯誤有的編譯器不能捕捉到。函數(shù)傳參數(shù)類似。
多維數(shù)組顯式初始化,只有第一維能夠推算出,其他維不能省略。
第九章 字符串、字符和字節(jié)
無符號數(shù)的謹(jǐn)慎使用:strlen返回?zé)o符號數(shù),因此if(strlen(x) - strlen(y)>=0) ...永遠(yuǎn)是真。這種情況下應(yīng)該寫為if(strlen(x)>=strlen(y)) ...或者采用強制類型轉(zhuǎn)換把其轉(zhuǎn)為int。
strtok保存它所處理的函數(shù)的局部狀態(tài)信息,因此不能用它同時解析兩個字符串。
字符串函數(shù)遇到NULL字節(jié)結(jié)束操作,想要處理非字符串?dāng)?shù)據(jù)時不受到這個限制,可以使用另一組相關(guān)的函數(shù):memcpy、memmove、memcmp、memchr、memset。
第十章 結(jié)構(gòu)和聯(lián)合
參數(shù)為結(jié)構(gòu)的函數(shù),傳遞指針比傳值調(diào)用更高效,這是因為后者需要建立一份結(jié)構(gòu)的拷貝。f(type_struct *s){s->x};調(diào)用即為f(&s)。如果對這個結(jié)構(gòu)的成員訪問次數(shù)超過3次,聲明為寄存器變量會更加有效。為了避免不適當(dāng)?shù)男薷模梢园褏?shù)聲明為const,將返回值賦給原結(jié)構(gòu)(或它的一個成員)。
位段只是進(jìn)行了簡單的了解,它是一種指定了成員長度的特殊結(jié)構(gòu)。
第十三章 高級指針話題
回調(diào)函數(shù)的使用可以解決類似于比較不明類型數(shù)據(jù)的問題,這里也是第一次系統(tǒng)地認(rèn)識回調(diào)函數(shù)。
第十四章 預(yù)處理器
消除多重包含的危險的方法,在每個頭文件寫入以下內(nèi)容:
第十五章 輸入/輸出函數(shù)
freopen用于打開(或重新打開)一個特定的文件流,原型:FILE *freopen(char const *filename,char const *mode, FILE *stream),其中最后一個參數(shù)就是需要打開的流。它首先試圖關(guān)閉這個流,然后用指定的文件和模式重新打開這個流,失敗返回NULL,成功返回第三個參數(shù)。
ungetc把先前讀入的字符返回到流中,使它可以以后被重新讀入?!禖程序設(shè)計語言》上有一個字符處理的例子用到了它,在此復(fù)習(xí)一下。當(dāng)fseek、fsetpos或rewind改變流的位置時,所有退回的字符都將被丟棄。
gets和puts與fgets和fputs的區(qū)別在于,gets讀取一行輸入時,并不在緩沖區(qū)存儲結(jié)尾的換行符,puts寫入一個字符串時,它在字符串寫入后向輸出再添加一個換行符。另外gets不判斷緩沖區(qū)長度,而這會造成危險。
feof判斷流是否處于文件尾,ferror報告流的錯誤狀態(tài),clearerr對指定流的錯誤標(biāo)志進(jìn)行重置。
tmpfile創(chuàng)建一個臨時文件保存數(shù)據(jù),程序結(jié)束時就被刪除。臨時文件的名字由tmpnam創(chuàng)建。
第十六章 標(biāo)準(zhǔn)函數(shù)庫
volatile是類型修飾符,被設(shè)計用來修飾被不同線程訪問和修改的變量,阻止編譯器以一種可能修改程序含義的方式“優(yōu)化”程序。
vprintf、vfprintf、vsprintf用于打印可變參數(shù)列表,功能類似于對應(yīng)的prinft等函數(shù),但參數(shù)是一個可變參數(shù)列表arg。
getenv獲取環(huán)境變量,如果找到就用指針返回,否則返回NULL。
locale是一組特定的參數(shù),每個國家可能不同,目的是增強C的世界范圍內(nèi)的通用性,不詳細(xì)記述。
對于十七章經(jīng)典抽象數(shù)據(jù)類型和第十八章運行時環(huán)境,前者已經(jīng)比較熟悉,后者與匯編結(jié)合緊密,只是粗略瀏覽了一下,這本書姑且算是看完了。
新聞熱點
疑難解答
圖片精選