Linux C 一站式學習 第一部分基礎知識

1. 聲明和定義

C 語言中的聲明(Declaration)有變量聲明,函數聲明和類型聲明三種。

如果一個變量或函數的聲明要求編譯器爲它分配存儲空間,那麼也可以成爲定義(Definition),因此定義是聲明的一種。分配存儲空間的函數聲明可以稱爲函數定義。


2. 變量命名

標識符:C語言中變量,函數名,宏定義,結構體成員名等都通稱爲標識符(Identifier)。

一般來講應避免使用以下劃線開頭的標識符,以下劃線開頭的標識符只要不和C語言關鍵字衝突都是合法的,但是往往被編譯器用作一些功能擴展(如第18.4節講的gcc的_attribute_語法),C標準庫也定義了很多以下劃線開頭的標識符留作內部使用,所以除非對編譯器的特徵和C標準庫的實現特別清楚,一般應避免使用這種標識符,以免造成命名衝突。


3. 函數聲明與函數定義

只有帶函數體的聲明才叫做定義。



4. 記住“先聲明後使用”的原則。(注意順序)


5. 形參和實參

形參想到與函數中定義的變量,調用函數傳遞參數的過程相當於定義形參變量並且用實參的值來初始化。


6. man 命令介紹



7. 局部變量可以用類型相符的任意表達式來初始化,而全局變量只能用常量表達式來初始化。


局部變量在使用前一定要先賦值,不然會系統會賦一個不確定的值。

8. 在一個函數體中可以聲明另一個函數,但不能定義另一個函數,C 語言不允許嵌套定義函數(注:gcc的擴展特性允許嵌套定義函數)。

9. 學習編程語言:



10. 結構體

(1). 定義

(1.1).

  1. // complex_struct爲標識符(名字),這種標識符在C語言中被稱爲Tag
  2. struct complex_struct {
  3.    double x, y;
  4. };
  5. // 注:結尾必須加分號
(1,2). 定義變量
A. 帶Tag(標識符)的結構體,可以定義變量
  1. // 後面的 z1,z2爲定義的變量
  2. struct complex_struct {
  3.    double x, y;
  4. } z1, z2;
  5. // 對於帶Tag的結構體,可以像基本類型那樣定義變量
  6. struct complex_struct z3, z4;
B. 不帶的結構體
  1. // 不帶Tag,這樣的結構體不能再定義額外的變量
  2. struct {
  3.    double x, y;
  4. } z1, z2;

11. 枚舉常量使用一種整型,其值是在編譯時確定。

12. 數組

(1). 數組不能相互賦值或者相互初始化。錯誤的例子

  1. // 下面的例子是錯的
  2. int a[5] = {4, 3, 2, 1};
  3. int b[5] = a; // 這樣是錯的
  4. a = b; // 這樣相互賦值也是錯誤的
(2). 數組不能相互賦值,也就不能用數組類型作爲函數的參數或者返回值。錯誤的例子:
  1. // 下面是錯誤的例子
  2. // 定義參數爲數組的函數,這樣是錯誤的
  3. void foo(int a[5])
  4. {
  5.    ...
  6. }
  7. // 調用
  8. int array[5] = {0};
  9. foo(array);
(3). 對數組類型有一條特殊規則,導致的這個問題。
數組類型做右值使用時,自動轉換成指向數組首元素的指針。所有上面的函數調用其實是傳遞一個指針類型的參數,而不是數組類型的參數。


13. 編譯器的工作分爲兩個階段,先是預處理(Preprocess)階段,然後纔是編譯階段。用gcc的-E選項可以看到預處理之後、編譯之前的程序。

像 #include 和 #define 這種以 # 號開頭的行稱爲預處理指示(Preprocess Directive)。使用 cpp ***.c 也可查看預處理的結果,它只做預處理而不做編譯,cpp 表示 C preprocessor。


14. #define

首先,define 不僅用於定義常量,而且可以定義更復雜的語法結構,稱爲宏(Macro)定義。其次,define 定義是在預處理階段處理的,而枚舉是在編譯階段處理的。


15. 字符串

每個字符串末尾都有一個字符"\0"做結束符,這裏的\0是ASCII碼的八進制表示,也就是ASCII碼爲0的Null字符,所以字符串也稱爲“以Null結尾的字符串”。


16. 多維數組

注意:除了第一維的數組長度可以有編譯器自動計算而不需要指定,其他各維的都必須明確指定長度。

eg:

  1. int a[][2] = {{1,2}, {3, 4}, {5,}};

17. gdb:使用gdb工具調試程序


斷電相關:


觀察點:


如果某個函數的局部變量發生訪問越界,有可能並不立即產生段錯誤,而是在函數返回時產生段錯誤。


18. 時間複雜度



19. 排序

(1). 插入排序:時間複雜度爲O(n^2);

(2). 歸併排序:時間複雜度爲O(nlgn);

        步驟:        

        a: Divide: 把長度爲n的輸入序列分成兩個長度爲n/2的子序列;

        b: Conquer: 對這兩個子序列分別採用歸併排序。

        c: Combine: 將兩個排序好的子序列合併成一個最終的排序序列。

(3). 快速排序


20. 查找

(1). 線性查找

(2). 折半查找:從一組排好序的序列中找出某個元素的位置,可以使用折半查找。


21. 斷言(Assertion):有效地測試程序

相關頭文件:assert.h


只Debug時調用測試代碼,Release時不調用:

(方式一). #define NDEBUG:測試代碼只在開發和調試時有用。如果在包含assert.h之前定義一個NDEBUG宏(表示No Debug),就可以禁用 assert.h 中的 assert 宏定義,這樣代碼中的所以 assert 測試都江不起作用。

Eg:

  1. #define NDEBUG // 必須在頭文件assert.h之前定義
  2. #include <stdio.h>
  3. #include <assert.h>
(方式二). 在編譯命令行中加入 -NDEBUG 選項就行。這樣不必修改源文件,而且這樣相當於在源文件開頭定義了 NDEBUG 宏。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章