C Primer Plus(三)
重讀C Primer Plus ,查漏補缺
重讀C Primer Plus,記錄遺漏的、未掌握的、不清楚的知識點
檔案輸入/輸出
1、fgets函式在讀取檔案內容時會將換行符讀入,但gets不會,fputs函式在寫入檔案時不會追加一個換行符,但puts會,應該對應配合使用。
2、不同作業系統下,以文字方式開啟檔案,幾乎沒有區別,但由於不同作業系統檔案結尾的的識別符號不同,以二進位制方式開啟時,可能會將結尾識別符號錯誤輸出。
3、對於大型檔案,有兩個特殊的函式提供支援:
1 int fgetpos(FILE * restrict stream, fpos_t * restrict pos); 2 int fsetpos(FILE * stream, const fpos_t *pos);
其中,fpos_t是通過其他型別定義的檔案定位型別,在使用上述函式時,fsetpos中的pos必須是通過fgetpos函式獲得的。當兩個函式執行成功時,會返回0。
4、其他標準IO函式
1 size_t fwrite(const void * restrict ptr, size_t size, size_t nmemb, FILE* restrict fp); 2 size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE* restrict fp); 3 // 是否到達檔案結尾 4 int feof(FILE* fp); 5 // 是否發生讀寫錯誤 6 int ferror(FILE* fp); 7 // 將字元迴流進緩衝區 8 int ungetc(int c, FILE* fp) 9 // 立刻將緩衝區內容寫入檔案 10 int fflush(FILE* fp) 11 // 替換緩衝區 12 int setvbuf(FILE* restrict fp, char * restrict buf, int mode, size_t size)
當然,上述的一些函式在目前的VS Studio中會被認為是不安全的函式,已經過時。
結構和其他資料格式
5、C99標準下支援對結構體初始化時的任意欄位賦值:
1 struct book gift = {.value=25.99, .author="Harry Potter", .title="Yoo"}; 2 // 此時 0.25 會被賦給定義結構體時author後的那個成員,即便那個成員已經被初始化過。 3 struct book gift = {.value=25.99, .author="Harry Potter", 0.25};
6、對於結構體陣列,陣列名不是其首個元素的地址,需要引用首個元素再取地址。
7、在結構中一般使用字元陣列,而不使用字元指標,結構中的字元指標無法很好的初始化地址,這樣會有使用上的風險,所以結構中的字元指標最好只指向那些字串常量或者是指向由malloc分配的記憶體。
8、C99標準對結構也支援複合文字,同時複合文字的結構也可以作為函式引數,也可以取地址,也和普通變數有相同的生存週期,宣告方式如下:
1 (struct book) {"The Idiot", "Fyodor Dostoyevsky", 6.99}
9、C99支援一種伸縮型陣列成員,這個成員必須是結構中最後一個成員,而且不是唯一一個成員,就像宣告普通陣列一樣,但括號內為空,這個成員不會在聲明後立即存在,實際上,C99希望使用malloc為這樣含有伸縮型成員的陣列分配空間。
1 struct flex{ 2 int count; 3 double avreage; 4 double scores[]; // 伸縮型成員 5 } 6 struct flex * pf; 7 pf = malloc(sizeof(struct flex) + 5*sizeof(double)) 8 pf->count = 5; 9 pf->scores[2] = 2.99;
10、對於C中的列舉型別,某些屬性不能順延至C++,例如C允許對列舉做++運算,但C++不允許。
1 enum spectrum {red, yellow, green, blue}; 2 spectrum color; 3 for(color = red; color != blue; color++);
11、在C中,對於同一作用域下的標記和變數名可以使用同一個名字,因為對於標記(列舉、結構,聯合),他們使用的名字空間與普通變數不同,但C++中不可以,例:
1 struct complex{double x, double y}; 2 int complex; // 在C中不會引起衝突,但C++中則不允許
12、對於函式指標執行函式時,會出現兩種語法,ANSI C把他們視為等價的。
1 void ToUpper(char *); 2 void (*pf) (char*); 3 char str[] = "hello"; 4 pf = ToUpper; 5 (*pf)(str); // 語法1 6 pf(str); // 語法2
位操作
13、為什麼一個位元組可以表示的有符號整數的範圍是-128~+127?
看這裡:https://www.cnblogs.com/Dylan7/p/12649972.html
14、計算機中小數是如何表示的?(一部分表示指數,一部分表示小數,有精確度問題)
15、對位進行操作的第二種方法就是位欄位(從沒用過,細節可以用到時再研究),位欄位好比一個結構體,但其中的成員,代表的是某幾位上的值,好處是避免了通過複雜的位運算去控制某些位上的值,宣告例如:
1 struct box 2 { 3 unsigned int opaque :1 // 整體結構的對齊補齊依據無符號整型 4 unsigned int fill_color :3 // 數字代表需要幾位來表示這個欄位 5 unsigned int :4 // 可以跳過一些位 6 unsigned int show_border :1 // 但一個欄位不能橫跨兩個無符號整型的邊界 7 } 8 struct box b; 9 b.fill_color = 7; // 不可以超過欄位所佔用的位可表示的上限
C前處理器和C庫
16、程式翻譯的第一步,在預處理前,編譯器會對程式碼做一些翻譯,將程式碼中出現的字元對映到源字符集(用來處理多位元組字元和使C外觀更加國際化的三元字元擴充套件),接著查詢反斜槓後緊跟換行符的例項,將其轉換為一行,然後將文字劃分為預處理的語言符號序列以及空白字元及註釋序列(將用一個空格代替一個註釋),最後進入預處理階段,尋找每一個預處理指令。
17、 幾個巨集定義
1 #define F(x) #x // #將語言符號字串化 2 #define F(x) F##x // ##將兩個語言符號組成一個語言符號 3 #define F(x,...) printf("x", __VA_ARGS__) // ...和__VA_ARGS__,可變引數(必須為最後一個引數)
18、#if 指令後面跟常量整數表示式,可以與 #elif 配合使用,例如:
1 #if 1 == SYS 2 ... 3 #elif 2 == SYS 4 ... 5 #endif
同時,還有以下新的實現方式,defined 是一個預處理運算子,如果引數使用#define定義過,defined返回1,否則返回0。
1 #if defined(INMPC) 2 ... 3 #elif defined(VAX) 4 ... 5 #endif
19、#line 用於重置__LINE__,__FILE__巨集所報告的行數
#error 指令使前處理器可以發出一條錯誤資訊
1 #line 10000 2 #line 10 cool.c" 3 #if __STD_VERSION__ != 199901L 4 #error Not C99 5 #endif
20、C99 提供了_Pragma前處理器運算子,可以將字串轉換成常規的編譯指示
1 _Pragma("c99 on") 等價於 2 #pragma c99 on
21、行內函數不會在偵錯程式中顯示,例如使用gdb除錯時,有些行內函數無法被手動執行,同時行內函數具有內部連結屬性,所以在多檔案程式中,使用其他檔案的行內函數時,要單獨宣告一次,並且在嘗試獲 取行內函數的地址時,編譯器都會產生非行內函數,也就是說可能產生外部定義的函式。
23、在main()函式結束時,會隱式地呼叫exit()函式,同時,可以通過atexit()函式,向exit()註冊在程式允許結束時執行的函式,ANSI C保證可以設定至少32個函式,按照先設定後執行的順序執行,atexit()函式接受一個返回值為void,引數也為void的函式指標作為唯一引數。
24、memcpy()與memmove()兩個函式的區別在於宣告上,以及memcpy()會假定兩個記憶體區沒有重疊。
1 void *memcpy(void * restrict s1, const void * restrict s2, size_t n); 2 void *memmove(void *s1, void *s2, size_t n);
25、可變引數的相關內容包含在stdarg.h標頭檔案中,使用起來比較複雜,包括初始化可變引數列表,遍歷列表,清理列表,拷貝列表等一系列操作,需要時再研究。
高階資料表示
26、 這章沒什麼新奇內容,但它告訴我們,用C可以實現很多複雜的資料結構。
2020年4月16日,星期五,晚23點09分,首次完整讀完這本書,共勉。
學如逆水行舟,不進則退;心似平原放馬,易縱難收。
&n