C語言全面總結-3

摳腳大漢的爺爺發表於2020-12-16

C語言基本知識點複習-3

typedef & define

typedef 是一個C語言中的關鍵字 用來為一個資料型別取別名 以增加程式碼的可讀性 用typedef定義陣列、指標、結構等型別會帶來很大的方便 不僅使程式書寫簡單 也使意義明確 增強可讀性。
define 是一個C語言中的指令 不緊可以為型別取別名 還可以用於常量 變數 和開關編譯等
typedef和define的區別

  1. typedef是關鍵字 在編譯的時候起作用 會檢查資料型別
    define是一個預處理指令 在預處理階段對程式碼進行替換 所以巨集定義不佔用編譯時間
  2. define沒有作用域 而 type有自己的作用域
  3. 在對指標使用時有區別
    比如:
    先定義
    #define int * INT1
    typedef int * INT2
    INT1 a,b;=====>int *a,b; 表示建立了一個int型指標a和一個int 型變數b
    INT2 a,b; =====>int *a,*b; 表示建立了兩個int指標a和b
    用INT1和INT2定義的a,b結果會不一樣 由此可見define僅僅是做一個文字上的簡單替換 而typedef不僅替換文字 同時還兼顧了替換的型別的功能

當用typedef 為結構體取別名時
正常我們定義結構體一般都是 struct + structName {…}; 這樣既沒有很好的可讀性 而且每次建立新的結構體變數時都要寫 struct +structName + structA 就很麻煩
所以用typedef為結構體取別名就很方便 例如:

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

這樣就可以直接用book來代表struct Books 這一串 既簡便又增加了可讀性
當然還有進階版本 直接定義結構體+結構體指標升級套餐

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book,*bookPtr;

這個程式碼的意思就是為struct Books取別名為book 為struct Books *取別名為bookPtr

程式記憶體分佈和記憶體管理

一般我們講的程式記憶體 比如說計算機當前執行了三個程式 則對於每一個程式都會將physical memory實體記憶體的一部分對映成一塊完整的虛擬記憶體 讓每個程式都以為自己擁有了完整的記憶體空間 這樣子可以極大的方便了資料和程式碼的組織
一個程式所對映的虛擬地址如下(virtual memory 虛擬記憶體)
在這裡插入圖片描述
上邊的圖中 大致把VM分成了六個大塊 核心 、棧、堆、資料段、程式碼段、不可訪問的空間 但其中核心和不可訪問段是使用者無法訪問的
一般我們無法直接檢視一個exe可執行檔案的內容 但是在linux下可以使用" readelf 檔名 -s " 指令來檢視一個可執行檔案的section段資訊
這裡的一些 像11.13 .15等都對應著上圖VM中不同的段位置
在這裡插入圖片描述

棧的全稱為(run-time stack)執行時棧 意味著在執行時棧的大小是變化的 一般棧中儲存的是區域性變數 一旦一個函式被呼叫 則會建立一幀新的棧用來存放該程式的區域性變數和形參 當然在實現函式的巢狀呼叫時 還要儲存當下的程式碼地址和相關暫存器的值 以便於保護現場和恢復現場 但是棧的空間很小 一般只有8M
如果超出了這個界限則會產生 “棧溢位” 導致程式崩潰 所以一邊程式用不宜呼叫太深的巢狀函式 和太多的區域性變數

堆的全稱為(run-time heap)執行時棧 所以堆也是大小變化的 主要用來儲存使用者自定的資料空間 一般有以下幾個函式建立和釋放
malloc() //建立一個連續的自定義空間
calloc(n,m)//建立n個每個m大小的自定義空間
realloc()//為已有的自定義空間更改大小
free()//釋放自定義空間
!!! 建立動態記憶體空間後記得要用free釋放

資料段

用來存放全域性變數 靜態變數 其中又分三段
.bss 用來存放未初始化靜態資料 比如a[100] 這個陣列沒初始化 因為系統會對為初始化的靜態資料自動初始化為0 但是如果直接存100個0在a[100]裡有點浪費空間 所以在.bss這一段中就可以標記一下 說這個陣列是未初始化的 就不用記100個0
.data 用來存放已初始化的靜態變數
.rodata 顧名思義就是隻讀(read only data)用來存放常量

程式碼段

用來存放使用者程式碼和系統程式碼
使用者程式碼好理解
系統程式碼就是系統給可執行檔案自動新增的一個“初始化程式碼”包括環境變數的準備 命令列引數的組織和傳遞 這部分資料在棧底 緊挨著核心的那裡

一些細節點

  1. 棧底的那部分環境變數開始執行後就不會更改 執行過程中更改的環境變數會儲存在堆中
  2. 棧和堆都是動態變化的 執行過程中 棧從上往下增長 堆從下往上增長(上邊的圖也可以看出來)
  3. 靜態資料包括:全域性變數和static修飾的區域性變數
  4. 應儘量避免濫用靜態變數 first 因為靜態變數在整個程式執行期間都生存的 會佔空間 second 例如全域性變數屬於共享資源 在多執行緒中容易產生競爭 需要小心的互斥以保護

檔案I/O

I/O可以使用系統IO和標準IO
系統IO是作業系統訪問檔案的API 介面 例如Linux裡面的open()close()
標準IO是C語言標準庫中提供的結構 例如fopen()fclose()
在這裡插入圖片描述
當使用fopen時系統會返回檔案指標int *File
open()會返回一個檔案描述符 int file
一遍檔案描述符會從3開始 因為0.1.2已經分別被標準輸入(鍵盤)標準輸出(顯示器 )和標準出錯所佔據
使用檔案指標或檔案描述符就可以對檔案進行操作了

小結

C語言基礎就告一段落了 其實還有好多深入的知識點還沒有複習到 比如連結串列結構 指標的詳細 等等… 後面會繼續學習計組計網 資料結構演算法 和作業系統 到時候再對進階的一些C語言知識點做進一步專門的總結歸納吧

嗜好太多 能力太小~

相關文章