C語言-學習筆記 --《c primer plus》
阿新 • • 發佈:2021-08-04
C語言
1. C語言基礎
- 命名只能用字母、數字、下劃線,名稱第一位不能為數字。
- 函式包含:函式原型、函式呼叫、函式定義。 函式原型可以省略引數名,函式定義中不可以。
- 程式錯誤:語法錯誤、語義錯誤。
- 兩個很大的資料相減,浮點數損失精度更多。因為任何一個區間內都存在無窮個實數,計算機的浮點數不能表示區間內的所有值。浮點數通常是實際值的近似值,例如,7.0可能被儲存為6.9999。
- (1111)2=2**5 -1 二進位制1111等於2的5次方減一。
- 100的16進位制(%x)表示0x64,八進位制(%o)0144。
- char grad='a'; 用單引號框起來的是字元對應的ASCII碼。" "雙引號表示字串。
- C語言中將字元常量視為int型,而非char型。char letter='B';中B對應為66,存在32位儲存單元中,現在grade擷取後八位放在8為儲存單元中。
- int 32位;float 32位,數值符號位1,指數位8(第一位為指數符號1),尾數位23,有6-7位有效數字。double b4位,符號1位,指數11位,尾數52位,有效數字15-16位。浮點型常量寫法,如-1.56e3,3.4E5。沒有後綴的浮點型,預設是double。
- C語言數值型別分為整數型別、浮點數型別。使用可移植型別可以保證資料型別位數是自己要求的位數,遮蔽掉不同系統的差異。一般包含精確寬度整數型別(C90)、最快最小寬度型別(C99、C11)。
- %zd z是修飾符、d是轉換字元,修飾符不可以單獨使用。
- ++a是a先加1再計算,a++是運算結束後加1。
- 形參中的char、short會自動升級成int,float會變成double。這是隱式型別裝換,在使用時會自動進行裁切。主要是把所有的運算元轉換為統一的長度,極大地簡化了程式碼的生成,這樣,壓到堆疊中的引數都是同一長度的,所以執行時系統只需要知道引數的數目,而不需要知道它們的長度,是一種臨時手段。
- 條件運算子(?: 三元運算子)比if else更簡潔。
- 回顯輸入意味著使用者輸入的字元直接顯示在螢幕上,無回顯輸入意味著擊鍵後對應字元不顯示。
- 可使用<符號重定向輸入流,使用>符號重定向輸出流。
- scanf 會把換行符留在輸入佇列。
- 遞迴每次呼叫都會建立一組變數,使用記憶體更多,且由於函式每次呼叫會花費時間,所以執行速度更慢,但在某些場景下解決更簡單(如處理倒序)。
- C90不支援變長陣列a[n](VLA,n為整型變數),C99支援VLA(不能使用static extern修飾),C11可選支援。
- 字串初始化用指標與字元陣列的區別:1、陣列名是常量,而指標名是變數。2、初始化陣列把靜態儲存區的字串拷貝到陣列中,而初始化指標只把字串的地址拷貝給指標。建議在把指標初始化為字串字面量時使用const限定符。3、不修改字串,不要用指標指向字串,需要修改字串用字元陣列。
- gets()、puts()在C11中被廢棄,可用fgets()、fputs()、gets_s()(c11新增可選支援)替代。
2. 儲存類別、連結和記憶體管理
- 儲存期描述了通過識別符號訪問的物件的生存期。分為:靜態儲存期、執行緒儲存期、自動儲存期、動態分配儲存期(malloc、calloc)。
- 靜態儲存期,它在程式執行期間一直存在。檔案作用域變數具有靜態儲存期。塊作用域變數也可以具有靜態儲存期,加上static即可。自動初始化為0。
- 執行緒儲存期用於併發程式設計,具有執行緒儲存期的變數,從被宣告時到執行緒結束一直存在。用關鍵字 _Thread_local宣告時,每個執行緒都有一個私有備份。
- 塊作用域的變數通常具有自動儲存期,進入這些塊時,為這些變數分配記憶體,離開塊時釋放。
- 識別符號用於訪問物件(儲存值的一塊記憶體),可以用作用域、連結描述識別符號的可見性。
- 作用域描述程式中可訪問識別符號的區域。分為塊作用域、函式作用域、函式原型作用域和檔案作用域。
- 連結分為:外部連結、內部連結、無連線。具有塊作用域、函式作用域、函式原型作用域的變數都是無連結,是私有的。具有檔案作用域的變數可以使外連結(預設extern)或者內部連結(static)。
- 自動變數是屬於自動儲存期的變數,具有自動儲存期、塊作用域且無連結。可顯示使用auto(C++auto含義完全不同)。不會初始化。
- 暫存器變數同自動變數,不過是把變數放在暫存器中。不保證在暫存器中,無法獲取地址,資料型別有限(暫存器位數有限)。
- 塊作用域的靜態變數,具有靜態儲存期的變數,用static宣告。
- 外部連結的靜態變數,具有檔案作用域,外部連結和靜態儲存期。用extern宣告,只能初始化一次且必須在定義時進行。
- C99和C11要求識別區域性識別符號的前63個字元和外部識別符號的前31個字元。之前標準是前31和前6個。
- 內部連結的靜態變數,具有靜態儲存期、檔案作用域和內部連結。用儲存類別說明符static宣告。
- 儲存類別說明符:auto、register、static、extern、_Thread_local、typedef。
- 函式也有儲存類別,使用static說明函式為模組私有,可以解決命名衝突,預設是extern。
- 可以使用malloc、calloc(初始化為0)函式來自行分配記憶體,不過最後注意要free記憶體,防止記憶體洩漏。
- restrict,只能用於指標,表明該指標是訪問資料物件的唯一且初始的方式。
- volatile限定符告知計算機,代理(其他程式)可以改變該變數的值。涉及到編譯器的優化。
- _Atomic型別限定符,用在多執行緒中,宣告原子型別的變數,C11可選支援。
3. 檔案輸入輸出
- C把檔案看作是一系列連續的位元組,每個位元組都能被單獨處理。提供兩種檔案模式:文字模式、二進位制模式。
- fopen()的模式字串,r、w、a、x(C11)。getc(fp)、putc(fp)是從指定檔案中獲取一個字元。需要fclose()關閉。
- fseek()可以在開啟的檔案中,直接移動到任意字元。檔案起始點模式有SEEK_SET、SEEK_CUR、SEEK_END。
- ftell()返回檔案中當前位置。
- fgetpos()、fsetpos()是處理較大檔案的新定位函式。
- fread()、fwrite(),在要求不損失精度的條件下儲存和恢復值,用函式採用二進位制模式進行讀寫。缺點:不同的作業系統可能使用不同的二進位制表示法,所以資料檔案可能具有不可移植性;甚至一個作業系統,不同的編譯設定也會導致不同的二進位制佈局。
4.C前處理器和C庫
- #define 來定義巨集,包含明示常量、任何字串、字元常量、類函式巨集(巨集帶引數)、也可以為空,只做引數替換,不進行計算。替換部分可以用##將兩個記號組合成一個記號、用#組合字串、...與__VAR_ARGS__可用來自定義可變引數的巨集,只能放在最後面。
- #include會檢視後面的檔名並把檔案的內容包含到當前檔案中,即替換原始檔的#include指令。
- 標頭檔案中最常用的形式包含明示常量、巨集函式、函式宣告(函式原型)、結構模板宣告、型別定義。
- #undef 用於取消已定義的#indefine指令,也就是取消已經定義的巨集。
- 條件編譯指令,#ifdef、#else、#endif,#ifdef max表示是否#define定義了MAX、或者包含了標頭檔案,可以用來標記C語句塊。與之相反的還有#ifndef、#else、#endif。主要用於防止多次包含標頭檔案。
- #if、#elif與if、else if相似,後面跟整型常量表達式,如果表示式為非零,則表示式為真。
- 預定義巨集:__DATE__,__FILE__,__LINE__,__STDC__,__STDC_HOSTED__,__STDC_version__,__TIME__,__func__。
- #line 重置__FILE__和__LINE__報告的檔名和行號。
- #error指令讓前處理器發出一條錯誤資訊,該訊息包含指令中的文字。
- #pragma編譯指示,用於控制分配給自動變數的記憶體量、設定錯誤檢查嚴格程度、啟用非標準語言特性等。
- _GENERIC泛型選擇表示式,常用作#define巨集定義的一部分。
- 行內函數(C99),標準規定具有內部連結的函式可以成為行內函數,最簡單的使用方法是使用函式說明符inline和儲存類別符。可以放在標頭檔案中。因為是直接替換函式程式碼,所以可以避免函式呼叫的開銷(建立呼叫、傳遞引數、跳轉到函式程式碼並返回)。C99
- _Noreturn,這是第二個函式說明符,表明函式呼叫後,不返回主調函式。exit()和abort()都使用此宣告。
- atexit(),在呼叫exit()退出時,呼叫最後註冊的函式。
- assert(),接受一個整型表示式作為引數(一般為條件表示式、邏輯表示式),如果表示式為假(非零),assert()巨集就在標準錯誤流(stderr)中寫入一條錯誤資訊,並呼叫abort()終止程式。可用#define NDEBUG禁用assert()。是在執行時檢查。
- _Static_assert(),可以在編譯時檢查assert()表示式,可以讓程式無法通過編譯。可以出現在函式中。C11
- 在stdarg.h中,提供一些變參巨集,即該巨集可以接受可變數量的引數。包含有:va_start()、va_arg()、va_end()、va_copy()、va_list等。
5.高階資料表示
- 使用抽象資料型別方法程式設計:
- ADT(抽象資料型別),以抽象、通用的方式描述一個型別,包括該型別的操作。
- 設計函式介面表示這個新型別。
- 編寫具體程式碼實現這個介面。
- 陣列的優點:C直接支援、提供隨機訪問;缺點:在編譯時確定大小、插入和刪除很費時。
- 連結串列的優點:執行時確定大小、快速插入和刪除元素;缺點:不能隨機訪問、使用者必須提供程式設計支援。
- 隨機訪問表示同一時間訪問一組序列中的一個隨意元件。對陣列而言,可以使用下標直接訪問該陣列中的任意元素。對連結串列而言,必須從首節點開始逐個移動到要訪問到的節點,是順序訪問。
- 二叉查詢樹樹是一種結合了二分查詢策略的連結結構,是一種有序的二叉樹。為了使左右子樹更加平衡,可以使用AVL(平衡二叉樹)。