C語言20條編程核心知識要點

      網友投稿 881 2022-05-29

      引言

      筆者有十余年的C++開發經驗,相比而言,我的C經驗只有一兩年,C比較簡單,簡單到《The C Programming Language》(C程序設計語言)只有區區的200多頁,相比上千頁的C++大部頭,不得不說真的很人性化了。

      C語言精簡的語法集和標準庫,讓我們可以把精力集中到設計等真正重要的事情上來,而不是迷失在語法的海洋里,這對于初學者尤其重要。雖然C語言有抽象不足的缺點,但我更喜歡它的精巧,只需要花少量的時間,研究清楚它每一個知識點,看任何C源碼就不會存在語法上的障礙,大家需要建立的知識共識足夠少,少即是多,少好于多。

      我教過6個人編程,教過HTML,教過JAVA,也教過C++。最近,我在教我小孩編程,他只有十歲,很多人建議我選擇Python,但我最終選擇了C語言,因為C語言簡單且強大,現在看來,好像是個不錯的選擇。

      類型

      C是強類型語言,有short、long、int、char、float、double等build-in數據類型,類型是貫穿c語言整個課程的核心概念。

      struct、union、enum屬于c的構造類型,用于自定義類型,擴充類型系統。

      變量

      變量用來保存數據,數據是操作的對象,變量的變字意味著它可以在運行時被修改。

      變量由類型名+變量名決定,定義變量需要為變量分配內存,可以在定義變量的同時做初始化。

      int i;

      float f1 = 0.5, f2= 0.8;

      常量

      const int i = 100;

      const char* p = "hello world";

      運行中恒定、不可變,編譯期便可確定。

      數組

      光有簡單變量顯然不夠,我們需要數組,它模擬現實中相同類型的多個元素,這些對象是緊密相鄰的,通過數組名+位置索引便能訪問每個元素。

      二維、三維、高緯數組本質上還是線性的,二維數組通過模擬行列給人平面的感覺,實際存儲上還是連續內存的方式。

      數組是靜態的,在定義的時候,數組的長度就已經確認,運行中無法伸縮,所以有時候我們不得不為應付擴充多分配一些空間。數組元素不管用多用少,它都在哪里,有時候,我們會用一個int n去界定數組實際被使用的元素個數。

      函數

      函數封裝行為,是模塊化的最小單元,函數使得邏輯復用變得可能。

      C語言是過程式的,現實世界都可以封裝為一個個過程(函數),通過過程串聯和編排模擬世界。

      用C語言編程,行為和數據是分離的。調用函數的時候,調用者通過參數向函數傳遞信息,函數通過返回值向調用者反饋結果。

      函數最好是無副作用的,函數內應該盡量避免修改全局變量或者靜態局部變量,更好的方式是通過參數傳遞進來,這樣的函數只是邏輯的盒子,它滿足線程安全的要求。

      有了變量和函數,就可以編寫簡單的程序了。

      控制語句

      ? 分支:if 、else、else if、switch case、?:

      ? 循環:while、do while、for

      ? break、continue、goto、default

      結構體

      build-in數據類型不足以描繪現實世界,或者用build-in類型描述不夠直接,結構體用來模擬復合類型,它賦予了我們擴充類型系統的能力,我們把類型組合到一起構建更復雜的類型,而每個被組合的成分就叫成員變量。

      結構體內的成分,對象通過點(.)運算符,指針通過箭頭(->)訪問成員。

      指針

      C語言的靈魂是指針,指針帶來彈性,指針的本質是地址。

      需要區分指針和指針指向的對象,多個指針變量可指向同一個對象,一個指針不能同時指向多個對象。

      指針相關的基本操作包括:賦值(修改指針指向),解引用(訪問指針指向的對象),取地址(&variable),指針支持加減運算。

      因為指針變量要能覆蓋整個內存空間,所以指針變量的長度等于字長,32位系統下32位4字節,64位系統下64位8字節。

      指針的含義遠比上述豐富,指針跟數組結合便有了指針數組(int* p[n])和數組指針(int (*p)[n]),指針跟函數結合便有了函數指針(ret_type (*pf)(param list)),指針跟const結合便有了const char*/char* const/const char* const,還有指向指針的指針(int **p)。

      既可以定義指向build-in數據類型的指針,也可以定義指向struct的指針,void*表示通用(萬能)指針,它不能被解引用,也不能做指針算術運算。

      函數指針與回調(callback)

      c source code被編譯鏈接后,函數被轉換到可執行程序文件的text節,進程啟動的時候,會把text節的內容裝載到進程的代碼段,代碼段是c進程內存空間的一部分,所以任何c函數都會占一塊內存空間,函數指針就是指向函數在代碼段的第一行匯編指令,函數調用就會跳轉到函數的第一個指令處執行。

      函數指針經常被用來作為回調(callback),c語言也會用包含函數指針成員的結構體模擬OOP,本質上是把C++編譯器做的事情,轉給程序員來做(C++為包含虛函數的類構建虛函數表,為包含虛函數的類對象附加虛函數表的指針)。

      字符串

      char*是一類特殊的指針,它被稱為c風格字符串,因為它總是以‘

      char*是一類特殊的指針,它被稱為c風格字符串,因為它總是以‘\0’作為結尾的標識,所以要標識一個字符串,有一個char*指針就夠了,字符串的長度被0隱式指出,跟字符串相關的STD C API大多以str打頭,比如strlen/strcpy/strcat/strcmp/strtok。

      ’作為結尾的標識,所以要標識一個字符串,有一個char*指針就夠了,字符串的長度被0隱式指出,跟字符串相關的STD C API大多以str打頭,比如strlen/strcpy/strcat/strcmp/strtok。

      內存和內存管理

      指針提供了c語言直接操作底層內存的能力,c程序區分棧內存和堆內存,棧內存是函數內的局部變量,它隨程序執行而動態伸縮,所以不要返回臨時變量的指針,棧內存容量有限(8/16M),所以我們要避免在函數內創建過大的局部變量,要警惕遞歸爆棧。

      堆內存也叫動態內存,它由一個叫動態內存配置器的標準庫組件管理,glibc的默認動態內存配置器叫ptmalloc,初始版本有性能問題,但后面用線程私有解決了競爭改善了性能。動態內存配置器是介于kernel與應用層的一個層次,從內核視角看ptmalloc是應用程序,從應用層來看ptmalloc又是系統庫。malloc跟free必須配對,這是程序員的職責,動態分配的內存丟失引用就會導致內存泄漏,指向已釋放的內存塊俗稱野(懸垂)指針。

      預處理

      從c source file到可執行程序需要經過預處理-編譯-匯編-鏈接多個階段,預處理階段做替換、消除和擴充,預處理語句以#打頭。

      宏定義,#define,宏定義可以用\做行連接,#用來產生字符串,##用來拼接,宏定義的時候要注意加()避免操作符優先級干擾,可以用do while(0)來把定義作為單獨語句,#undef是define的反操作。

      #if #ifdef #ifndef #else #elif #endif用來條件編譯,為了避免頭文件重復包含,經常用#ifndef #define #endif。

      #include用來做頭文件包含;#pragma用來做行為控制;#error用來在編譯的時候輸出錯誤信息。

      __FILE__、__LINE__、_DATE_、_TIME_、_STDC_等標準預定義宏可以被用來做一些debug用途。

      #typedef用來定義類型別名。比如typedef int money_t;money_t比int更有含義。

      typedef也能用來為結構體取別名,有時候會這樣寫:

      typedef struct

      {

      int a;

      int b;

      } xyz_t;

      這樣在定義結構體變量的時候就可以少敲幾下鍵盤。

      typedef也可以用來重定義函數指針類型,比如 typedef void (*PF) (int a, int b); PF是函數指針類型,而非函數指針變量。

      枚舉

      枚舉能增加代碼可讀性和可維護性,枚舉本質上是int,只是為了更有含義,將有限取值的幾個int值放在一組,比如定義性別:enum sex { male = 1, female };

      可以在定義的時候賦值,比如male=1,后面的值依次遞增1,如果不賦值則從0開始。

      聯合體(union)

      結構體和聯合體(共用體)的區別在于:結構體的各個成員會占用不同的內存,互相之間沒有影響;而共用體的所有成員占用同一段內存,修改一個成員會影響其余所有成員。

      union u_data

      {

      int n;

      char ch;

      double f;

      };

      其實本質上,聯合體就是對一塊內存的多種解釋,大小按最大的來。

      位域(bitfield)

      struct SNField

      {

      unsigned char seq:7 ;? ? ? ? // frame sequnce

      unsigned char startbit:1 ;? ?// indicate if it's starting frame 1 for yes.

      };

      節省空間,在面向底層的編碼,或者編寫處理網絡等程序時候用的比較多,注意這個語法特征是跟機器架構相關的。

      位操作

      1. 位與 &

      2. 位或 |

      3. 位取反 ~

      4. 位異或 ^

      5. 位移 << >>

      static、extern、register、volatile、sizeof

      1. static修飾全局函數,表示模塊內(編譯單元)內可用,不需要導出全局符號。

      2. static修飾局部變量,意味超越函數調用的生命周期,不存儲在棧上,只會被初始化1次。

      3. extern聲明外部變量。

      4. register,寄存器變量,建議編譯器將變量放在寄存器里。

      5. volatile,告訴編譯器不要做優化,每次從內存讀取,不做寄存器優化。

      6. sizeof求大小,可以作用于變量,類型,表達式

      可變參數

      void simple_printf(const char* fmt, ...)

      va_list、va_start、va_arg、va_end

      C的高級感

      1. 泛型:linux內核鏈表,通過offset和內嵌node,寫出泛型鏈表,參考:https://www.cnblogs.com/wangzahngjun/p/5556448.html

      2. OOP:通過定義帶函數指針成員變量的結構體,在運行中,為結構體對象設置上函數指針,模擬運行時綁定,實現類似OOP多態的感覺。

      GNU C擴展

      GNU C擴展不是標準C,建議以符合標準C的方式編寫C代碼,但如果你閱讀linux kernel code,你會發現有很多有趣看不懂的語法,它來自GNU C擴展,它確實也帶來了一些便利性。

      比如結構體成員可以不按定義順序初始化:

      struct test_t { int a; int b; };

      struct test_t t1 = { .b = 1, .a = 2 };

      比如可以通過指定索引初始化數組:

      int a[5] = {[2] 5,[4] 9};

      C語言的20條編程核心知識要點

      或 int a[5] = { [2] = 4, [4] = 9 };

      相當于int a[5] = {0, 0, 4, 0, 9};

      或者int a[100] = {[0 ... 9] = 1, [10 ... 98] = 2, 3};

      比如0長度數組

      struct foo

      {

      int i;

      char a[0];

      };

      比如用變量作為數組長度

      void f(int n)

      {

      char a[n];

      ...

      }

      比如case范圍,case 'A' ... 'Z'? ?case 1 ... 10

      比如表達式擴展({...}),比如三元運算符擴展...

      c語言 編程 c++

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:C語言編程核心要點,男人看了沉默,女人看了流淚
      下一篇:Splunk 架構:轉發器、索引器和搜索頭教程
      相關文章
      老色鬼久久亚洲AV综合| 亚洲午夜电影在线观看高清| 亚洲AV电影院在线观看| 国产国拍亚洲精品福利 | 亚洲av永久无码精品漫画| 亚洲精品视频免费观看| 激情小说亚洲色图| 亚洲AV无码精品国产成人| 亚洲欧美日韩中文无线码 | 亚洲高清有码中文字| 亚洲一区二区三区高清不卡| 亚洲伦理一二三四| 77777亚洲午夜久久多喷| 亚洲精品中文字幕无乱码麻豆| 久久精品国产99国产精品亚洲| 亚洲妓女综合网99| 亚洲五月综合缴情婷婷| 一本天堂ⅴ无码亚洲道久久| 日韩亚洲不卡在线视频中文字幕在线观看| 亚洲Av高清一区二区三区| 亚洲精品456人成在线| 亚洲av日韩aⅴ无码色老头| 亚洲av第一网站久章草| 亚洲国产成人精品91久久久| 亚洲国产成人精品91久久久 | 久久久亚洲精品视频| 18gay台湾男同亚洲男同| 亚洲黄色三级网站| 亚洲最新中文字幕| 亚洲宅男精品一区在线观看| 亚洲午夜理论片在线观看| 亚洲AV无码资源在线观看| 国产区图片区小说区亚洲区| 亚洲国产精品专区在线观看| 国产成人麻豆亚洲综合无码精品| 好看的亚洲黄色经典| 激情内射亚洲一区二区三区| 亚洲乱码卡一卡二卡三| 亚洲精品宾馆在线精品酒店| 九月婷婷亚洲综合在线| 国产成人精品日本亚洲专区61 |