本書封皮如下:
摘抄如下:
p13:可移植的代碼
一個嚴格遵循標準的程式應該是:
只使用已確定的特性
不突破任何由編譯器實現的限制
不產生任何依賴由編譯器定義或未確定的或未定義的特性的輸出
p31:在C語言中,const關鍵字並不真正表示常量,如
const int two=2;switch(i){ case 1:xxx case two:xxx ...}
報錯
p32:case標籤後面不加break語句導致的fall through現象,switch語句的預設行為在97%的情況下都是錯誤的
p38:當sizeof的運算元是個類型名時,兩邊必須加上括弧,但運算元如果是變數則不必加括弧,例如
sizeof asizeof(int)
p68:可以把typedef看成是一種徹底的封裝類型,它和宏的區別體現在兩個方面:
1、可以用其他類型說明符對宏類型名進行擴充,但對typedef所定義的類型名卻不能這樣做
#define peach intunsigned peach i; //正確typedef int banana;unsigned banana i; //錯誤
2、在連續幾個變數的聲明中,用typedef定義的類型能夠保證聲明中所有的變數均為同一種類型,而用#define定義的類型則無法保證
#define int_ptr int *int_ptr chalk,cheese;
變成
int * chalk, cheese; //chalk是一個int的指標,cheese是一個int
使用typedef則沒有這個問題
p87:定義指標時,編譯器並不為指標所指向的對象分配空間,它只是分配指標本身的空間,除非在定義時同時賦給指標一個字串常量進行初始化,但不能指望為浮點數之類的常量分配空間
char *p="breadfruit"; //正確float *pip=3.141; //錯誤
p93:如果函數庫的一份拷貝是可執行檔的物理組成部分,那麼我們稱為靜態連結;如果可執行檔只是包含了檔案名稱,讓載入器在運行時能夠尋找程式所需要的函數庫,那麼我們稱為動態連結
p102:Interpositioning就是通過編寫與庫函數同名的函數來取代該庫函數的行為,但很容易發生自己代碼中某個符號的定義取代函數中相同符號的意外。不僅你自己所進行的所有對該函數的調用將被自己版本的函數調用所取代,而且所有調用該庫函數的系統調用也將用你的函數取而代之。
p127:如果想返回一個指向在函數內部定義的變數的指標時,要把那個變數聲明為static,這樣就能保證該變數被儲存在資料區段中而不是堆棧中。
p153: malloc和free--從堆中獲得記憶體以及把記憶體返回給堆
brk和sbrk--調整資料區段的大小至一個絕對值
p158-159:
匯流排錯誤:幾乎都是由於未對齊的讀或寫引起的,之所以稱為匯流排錯誤,是因為出現未對齊的記憶體訪問請求時,被堵塞的組件就是地址匯流排,例如
union{ char a[10]; int i;}u;int *p=(int *)&(u.a[1]);*p=17; //p中未對齊的地址會引起匯流排錯誤
段錯誤:由於記憶體管理單元的異常所致,該異常通常是由於解除引用一個未初始化或非法值的指標引起的,例如
int *p=0;*p=17; //段錯誤
p161:通常導致段錯誤的原因
1、解除引用一個包含非法值的指標
2、解除引用一個null 指標
3、在未得到正確的許可權時進行訪問
4、用完了堆棧或堆空間
常見變成錯誤
1、壞指標錯誤:在指標賦值之前就用它來引用記憶體
2、改寫錯誤:越過數組邊界寫入資料,在動態儲存裝置的記憶體兩端之外寫入資料,改寫一些堆管理結構
3、指標釋放引起的錯誤:釋放同一個記憶體兩次,釋放一塊未曾使用malloc分配的記憶體,釋放仍在使用的記憶體,釋放一個無效的指標
p200:什麼時候數組和指標相同
數組聲明:
extern,如extern char a[]; 不能改寫成指標的形式
定義,如char a[10]; 不能改寫成指標的形式
函數的參數,如func(char a[]); 你可以隨自己喜歡,選擇數組形式或指標形式
數組在運算式中使用:
如c=a[i];你可以隨自己喜歡,選擇數組形式或指標形式
p201:什麼時候數組和指標是等同的:
1、運算式中的數組名被編譯器當作一個指向該數組第一個元素的指標
2、下標總是與指標的位移量相同
3、在函數參數的聲明中,數組名被編譯器當作指向該數組的第一個元素的指標
p207:沒有辦法把數組本身傳遞給一個函數,因為它總是被自動轉換為指向數組的指標
p209:數組和指標的可交換性總結:
1、用a[i]這樣的形式對數組進行訪問總是被編譯器改寫或解釋成像*(a+i)這樣的指標訪問
2、指標始終就是指標,它絕不可以改寫成數組
3、在特定的上下文中,也就是它作為函數的參數,一個數組的聲明可與看作是一個指標。作為函數參數的數組始終會被編譯器修改成為指向數組第一個元素的指標
4、當把一個數組定義為函數的參數時,可與選擇把它定義為數組,也可以定義指標。不管選擇哪種方法,在函數內部事實上獲得的都是一個指標
5、在其他所有情況下,定義和聲明必須匹配。如果定義了一個數組,在其他檔案對它進行聲明時也必須把他聲明為數組,指標也是如此
p225:數組和指標參數被編譯器修改
實參--------------------------------------所匹配的形參
數組的數組 char c[8][10]-----------------char(*)[10] 數組指標
指標數組 char *c[15]-------------------char **c 指標的指標
數組指標 char(*c)[64]-------------------char(*c)[64] 不改變
指標的指標 char **c----------------------char **c 不改變
p227:使用指標向函數傳遞一個多維陣列
my_function(int my_array[10][20]) //限制較大my_function(int my_array[][20]) //最右邊一維長度必須是20my_function(int (*my_array)[20]) my_function(char **my_array) //只有把二維數組改為一個指向向量的指標數組的前提下才可以這樣做
p234:建立動態數組的基本思路使用malloc()庫函數來得到一個指向一大塊記憶體的指標,例如:
#include<stdlib.h>#include<stdio.h>int size;char *dynamic;char input[10];size=atoi(fgets(input,7,stdin));dynamic=(char *)malloc(size);dynamic[0]='a';dynamic[size-1]='z';
p264:C++的一個簡單子集
盡量使用的C++特性:
1、類
2、建構函式和解構函式,但只限於函數體非常簡單的例子
3、重載,包括操作符重載和I/O
4、單重繼承和多態
避免使用的C++特性:
1、模板
2、異常
3、虛基類
4、多重繼承
p277:庫函數調用和系統調用
函數庫調用是語言或應用程式的一部分,而系統調用是作業系統的一部分,系統調用是在作業系統核心發現一個trap或中斷後進行的。庫函數調用通常比行內展開的代碼慢,因為它需要付出函數調用的額外開銷,但系統調用比庫函數調用還要慢很多,因為它需要上下文環境切換到核心模式。
p279:檔案描述符和檔案指標
所有操縱檔案的系統調用都接受一個檔案描述符作為參數,或者把它作為傳回值返回
檔案描述符就是開放檔案的每個進程表的一個位移量,用於unix系統調用中,用於標識檔案
檔案指標儲存了一個檔案結構的地址,檔案結構用於表示開放的I/O流,用於ANSI C標準的I/O庫調用中,用於標識檔案
小結:
這本書從seven那裡拿回來已經停留了很久,seven說這本書寫的不錯。如今總算把這本書看完,確實是有收穫。不得不說,最近實習看程式書的時間並不像去年那麼多了,估計大多花在看閑書上面了,爭取這個所謂的暑假再看點程式書吧,不斷學習才有進步。