[讀] C和指針 (Ch1 ~ Ch3)

Chapter 1

  • 使用預處理語句「註釋掉」代碼最安全數組

    #if 0
        // some statements
    #endif
  • printf返回輸出的長度(包括不可見字符),scanf只返回1(成功)或0(失敗)
  • scanf讀取輸入到數組時,直接寫數組名和&數組名效果相同安全

    int array[10]; // 如下兩種方式效果一致
    scanf("%s", array);
    scanf("%s", &array);
  • 賦值運算符的返回值大機率爲左值(C)或左值的引用(C++),但歸根究竟是一個undefined行爲,取決於編譯器的實現。但如下用法一般能夠接受:函數

    while ((ch = getchar()) != EOF && ch != '\n') // clear input buffer
        ; // 分號單獨寫一行,以避免把下一行代碼當成循環體

    且此處ch一般被聲明爲int,由於EOF其實是一個int編碼

  • 將做爲參數接收的數組名聲明爲const,能夠防止意外修改數組中的數據
  • gets函數的安全性問題在於,它讀取字符串時沒法知道其長度,當遇到超長字符串時很容易溢出

Chapter 2

  • 程序的編譯與執行操作系統

    • 首先看幾個容易混淆的擴展名指針

      • .out / .exe 可執行文件,Linux和Unix下用.out,Windows下用.exe
      • .o / .obj 編譯後產生的還沒有連接的中間文件,機器碼的初步形式,Linux和Unix下用.o,Windows下用.obj
      • .bin 單純二進制文件,多是代碼,也多是數據
    • 編譯code

      • Compile: source code > object code(對每個.c生成對應的.o / .obj
      • Link: object code > executable(連接全部.o / .obj文件生成一個完整的.out / .exe
    • 執行生命週期

      • 程序被操做系統加載入內存
      • 執行:使用運行時堆棧及靜態內存
      • 終止

Chapter 3

  • 字面值內存

    • 數字作用域

      • 在不明確指定類型時,它是能完整容納該值的最短類型
    • 字符

      • 使用L前綴指定字符爲寬字符常量(unicode只是寬字符編碼的一種,二者並不相等!

        wchar_t = L'X';
    • 字符串

      • ⚠️指向字符串常量的指針能夠被指向別的地方,但字符串常量是不能被改變的!

        char* strPtr = "blahblah";
        strPtr[2] = 'D'; // 非法操做!!
        strPtr = "Hmmm"; // It's Okay..
  • 沒有unsigned的浮點數!(第一次知道。。一個沒有想過的問題)
  • 聲明指針時,把星號緊挨變量寫是一個好習慣:

    int* a, b, c; // 很容易誤解爲a、b、c三個指針,而實際只有a是指針,b和c僅僅是int
  • 在聲明字符串指針的同時賦值實際意味將該指針指向字符串的首地址,畢竟C中根本沒有真正的字符串類型

    char *message = "Hello";
    // 實際上等價於
    char *message;
    message = "Hello"; // 而不是 *message = "Hello";
  • 用typedef定義指針類型

    以前一直不能理解這種習慣,以爲真的很容易把指針誤認爲數據,命名時加個Ptr後綴很差嗎??如今才知道原來是方便定義函數指針時用的。。soga

    #define charPtr char* // 危險!
    charPtr a, b, c; // 只有a被聲明爲指針,b和c爲char數據
    // ------------------------------------------------------
    typedef char *charPtr; // It's Okay..
    charPtr a, b, c; // a、b、c的類型都爲char*
  • ⚠️const(只表示道義上不會修改,硬要改仍是能夠用別的指針輕易繞開限制,防君子不防小人。。)

    • 聲明常量

      const int a;
      int const a;
      • 兩種方式徹底等價
      • 函數中聲明爲const的參數被調用時會獲得實參的值(?這句話沒有理解)
    • 聲明指針

      理解: 類型 、星號、變量名,這三個部分的相對順序老是固定的,星號左邊的const修飾數據,星號右邊的const修飾指針

      • 指向常量的指針變量(徹底等價)

        int const * p;
        const int * p;
      • 指向變量的常量指針

        int * const p;
      • 指向常量的常量指針

        int const * const ptr;
  • ⚠️連接屬性

    • 種類

      • external - 不論聲明多少次,位於幾個源文件,都表示同一實體
      • internal - 統一源文件內的聲明都爲同一實體
      • none - 每次聲明都是不一樣實體
    • 手動改變連接屬性

      • extern 指定爲external(代碼塊內部使用extern聲明變量能夠確保使用的是最外部的全局變量)
      • static 將缺省屬性爲external的聲明轉變爲internal屬性
  • ⚠️聲明 vs. 定義(從新理解了這兩個名詞。。)

    • 聲明Declaration

      • 僅僅是一個符號,不分配空間
      • 同一變量可聲明屢次
      • external聲明不是定義
    • 定義Definition

      • 定義也是聲明,真正地分配空間
      • 一個變量只能定義一次
      • 全部帶初始化的語句必定是定義。
  • 儲存類型

    • 靜態變量 - static

      • 靜態變量的初始化將會隨着程序被加載入內存同步完成,徹底沒有額外開銷
      • 未顯示指定值的靜態變量初始化爲0
      • 用途

        • 用於函數聲明或代碼塊以外的變量聲明:將external的變量改成internal(反正做用域和生命週期已經最大了)
        • 用於代碼塊內部變量聲明:將自動變量改成靜態變量(做用域和連接屬性不變)
    • 自動變量 - auto

      • 除了靜態變量和極少許寄存器變量外全部的變量都爲自動變量
      • 初始化和後期賦值的開銷相同(除了const,畢竟不存在後期賦值)
    • 寄存器變量 - register
相關文章
相關標籤/搜索