1. 程式人生 > 其它 >C語言-學習筆記 --《c primer plus》

C語言-學習筆記 --《c primer plus》

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.高階資料表示

  • 使用抽象資料型別方法程式設計:
    1. ADT(抽象資料型別),以抽象、通用的方式描述一個型別,包括該型別的操作。
    2. 設計函式介面表示這個新型別。
    3. 編寫具體程式碼實現這個介面。
  • 陣列的優點:C直接支援、提供隨機訪問;缺點:在編譯時確定大小、插入和刪除很費時。
  • 連結串列的優點:執行時確定大小、快速插入和刪除元素;缺點:不能隨機訪問、使用者必須提供程式設計支援。
  • 隨機訪問表示同一時間訪問一組序列中的一個隨意元件。對陣列而言,可以使用下標直接訪問該陣列中的任意元素。對連結串列而言,必須從首節點開始逐個移動到要訪問到的節點,是順序訪問。
  • 二叉查詢樹樹是一種結合了二分查詢策略的連結結構,是一種有序的二叉樹。為了使左右子樹更加平衡,可以使用AVL(平衡二叉樹)。