第三章、c語言高階階段

weixin_34377065發表於2018-02-27
Day9.指標和結構體

指標補充

1, 指標+1, 並不是真實的+1, 而是+4
2, 指標型別的兩個用途:
第一個用途, 取值的時候, 會根據指標型別所佔用的位元組去取出對應位元組的資料
第二個用途, 用於做加法運算, 指標+1, 其實是加上指標型別所佔用的長度 , 如果當前指標型別是int, 那麼+1本質上是加上4個位元組
3,只要一個指標指向了陣列, 那麼訪問陣列就有3種方式:
1. : ages[0];
2. : p[0];
3. : *(p + 0);
4,指標字串

    // 通過陣列儲存字串和通過指標儲存字串的區別
    // 如果通過陣列來儲存字串, 那麼字串是一個變數 str  可以修改
    // 如果通過指標來儲存字串, 那麼字串是一個常量 str2 不能修該
    // 陣列儲存的字串儲存在記憶體的棧中, 而通過指標儲存的字串儲存在常量區
    // 儲存在棧中的變數有一個特點, 當作用域結束系統會自動釋放該變數
    // 儲存在常量區中的值有一個特點, 不會被釋放, 而且多個相同的值對應的地址相同

// 利用指標儲存字串的應用場景
    for (int i = 0; i < 100; i++) {
        // 意味著會開闢100塊儲存空間來儲存xmg這個字串
        // 並且會釋放100次
//        char str5[] = "xmg";
        char *str6 = "xmg";
        printf("str5 = %s\n", str6);
    }
/*
     儲存字串的兩種方式:
     char str[] = "lnj";
     儲存的位置: 棧
     特點: 相同的字串會重複的分配儲存空間
           字串可以修改
     
     char *str = "lnj"
     儲存的位置: 常量區
     特點: 相同的字串不會重複的分配儲存空間
            字串不可以修改
     */

5,指向函式的指標

指向函式的指標的定義格式
     void (*funtionP) ();
     
     *    : 代表是一個指標
     funtionP    : 代表指標變數的名稱, 區分
     (*funtionP) : 代表將來指向一個函式
     void : 代表將來指向的函式沒有返回值
     ()   : 代表將來指向的函式沒有引數

int (*ageP)();
    ageP = getAge;
    printf("age = %i\n", ageP());
    
//    void (*sumP)(int v1, int v2);
    void (*sumP)(int, int);
    sumP = sum;
    sumP(10, 20);

    int (*sumP2)(int , int);
    sumP2 = sum2;
    printf("sum = %i\n", sumP2(10, 20));

結構體

// 1.定義結構體型別
    struct Person
    {
//        char name[20];
        char *name;
        int age;
        double height;
    };
    // 2.定義結構體變數
//    int num;
    struct Person p;
    // 注意: 陣列不能先定義再進行一次性的初始化, 所有下面的寫法是錯誤的
//    p.name = "lnj"; // name = {'l', 'n', 'j', '\0'};
    // 可以使用 結構體變數名稱.屬性的方式給結構體變數賦值
    p.name = "lnj";
    p.age = 30;
    p.height = 1.75;

/*
    int nums[] = {1, 3, 5};
    
    int nums[3];
    nums[0] = 1;
    nums[1] = 3;
    nums[2] = 5;
     
    int nums[3];
    nums = {1, 3, 5}; // 錯誤
    
    int nums[3] = {[1] = 2};
     printf("nums[0] = %i\n", nums[0]);
    */
    
    struct Dog
    {
        char *name;
        int age;
        double height;
    };
    // 1.定義的同時初始化
    struct Dog sd = {"wc", 13, 5.0};
    
    // 2.先定義再初始化(逐個初始化)
    struct Dog sd1;
    sd1.name = "ww";
    sd1.age = 5;
    sd1.height = 10.9;
    
    // 3.先定義再初始化(一次性初始化)
    struct Dog sd2;
    // 特別注意: 結構體和陣列有一點區別, 陣列不能先定義再進行一次性的初始化, 而結構體可以
    // 只不過需要明確的告訴系統{}中是一個結構體
    sd2 = (struct Dog){"xq", 8, 8.8}; // 陣列? 結構體?
    
    // 4.指定將資料賦值給指定的屬性
    struct Dog sd3 = {.height = 1.77, .name = "ww", .age = 33};
    
    printf("name = %s, age = %i, height = %lf\n", sd3.name, sd3.age, sd3.height);

列舉

    // 1.定義列舉型別
    // 定義列舉型別的規範
    // 列舉型別的取值一般以k開頭 後面跟上列舉型別的名稱  跟上當前取值的含義
    // 和結構體一樣, 列舉型別的名稱首字母大寫
    enum Season
    {
        kSeasonSpring,
        kSeasonSummer,
        kSeasonAutumn,
        kSeasonWinter
    };
    
    enum Gender
    {
        kGenderMale,
        kGenderFemale
    };
    
    enum Season es;
    es = kSeasonAutumn;
    
    enum Gender eg;
    eg = kGenderFemale;

區域性和全域性變數

/*
 區域性變數
 概念: 區域性變數就是定義在函式, 程式碼塊和函式形參列表中的變數, 我們就稱之為區域性變數
 作用範圍: 從定義的那一行開始一直直到遇到大括號結束或者遇到return為止
 特點: 
    相同作用域範圍內不能出現同名的區域性變數
    不同作用域範圍內出現同名的區域性變數, 內部的區域性變數會覆蓋外部的區域性變數
注意:
    區域性變數沒有固定的初始化值, 如果沒有對區域性變數進行初始化, 那麼區域性變數中是一些隨機的值, 所以在開發中千萬不要使用未初始化的區域性變數
 儲存位置:
    區域性變數儲存在棧中, 當作用域結束系統會自動釋放棧中的區域性變數
 
 
 全域性變數
 概念: 寫在函式,程式碼塊,形參列表外的變數, 我們就稱之為全域性變數
 作用範圍: 從定義的那一行開始一直直到檔案末尾(暫時這樣認為)
 特點:
    全域性變數和區域性變數可以同名
    如果存在和全域性變數同名的區域性變數, 那麼區域性變數會覆蓋全域性變數
注意:
    全域性變數如果沒有進行初始化, 那麼系統預設會將全域性變數初始化為0
 儲存位置:
    全域性變數儲存在靜態區中, 他會隨著程式的啟動而建立, 隨著程式的結束而結束
int num; // 全域性變數  num = 0;
/*
     static應用場景":
     當某個方法的呼叫頻率非常高, 而該方法中更有些變數的值是固定不變的
     那麼這個時候就可以使用static來修飾該變數, 讓該變數只開闢一次儲存空間
     這樣可以提高程式的效率和效能
     */
    static double pi = 3.1415926; // 固定

巨集

 巨集定義在什麼時候替換
 原始碼 --> 預處理 -->彙編 -->二進位制 -->可執行程式
 規範:
 一般情況巨集名都大寫, 多個單詞之間用_隔開, 並且每個單詞全部大寫
 有得公司又要求巨集名以k開頭, 多個單詞之間用駝峰命名
#define CLASS_COUNT 100
#define kClassCount 100
帶引數
#define PF(v1) ((v1)*(v1))
// 提前結束巨集定義的作用域
//#undef COUNT

typedef起別名

/*
 什麼是typedef, 它有什麼作用
 typedef可以給一個已知的資料型別起別名 (外號)
 
 利用typedef給資料型別起別名的格式:
 
 typedef 原有的資料型別 別名(外號);
 
 注意: 
 1. typedef不僅能給系統原有的資料型別起別名, 也可以給一個自定義的資料型別起別名
 2. 利用typedef給資料型別起別名, 並不會生成一個新的資料型別, 僅僅是給原有的型別起了一個別名而已
 */

int sum(int v1, int v2)
{
    return v1 + v2;
}

int minus(int v1, int v2)
{
    return v1 - v2;
}

// 注意: 如果是給指向函式的指標起別名, 那麼指向函式的指標的指標名稱就是它的別名
// functionPotinter == int(*functionPotinter)(int , int)
typedef int(*functionPotinter)(int , int);
int main(int argc, const char * argv[]) {
   
    // 9如何定義變數 :   資料型別 變數名稱;
//    int (*sumP)(int , int ) = sum;
    functionPotinter sumP = sum;
    printf("sum = %i\n", sumP(10 , 20));
    
//    int (*minusP)(int, int) = minus;
    functionPotinter minusP = minus;
    printf("minus = %i\n", minusP(20, 10));
    return 0;
}

// ----------------------------給指標起別名----------------------------
// String == char *
typedef char * String;
void test4()
{
    //    char *name = "lnj";
    // 注意: 如果給指標起別名之後, 那麼以後利用別名定義變數就不用再加*了
    String name = "lnj";
    printf("name = %s\n", name);
    
    
}

// ----------------------------給列舉型別起別名----------------------------

// 1.先定義列舉型別, 再給列舉型別起別名
/*
 enum Gender
 {
 kGenderMale,
 kGenderFemale
 };
 typedef enum Gender SEX;
 */

// 2.定義列舉型別的同時給列舉型別起別名
/*
 typedef enum Gender
 {
 kGenderMale,
 kGenderFemale
 } SEX;
 */

// 3.定義列舉型別的同時給列舉型別起別名, 並且省略列舉原有型別名稱
typedef enum
{
    kGenderMale,
    kGenderFemale
} SEX;

void test3()
{
    
    // 給列舉起別名
    //    enum Gender sex;
    SEX sex;
    sex = kGenderMale;
    /*
     定義列舉變數有3種方式
     1.先定義列舉型別, 再定義列舉變數
     2.定義列舉型別的同時定義列舉變數
     3.定義列舉型別的同時定義列舉變數, 並且省略列舉型別名稱
     */
    /*
     enum Gender2
     {
     kGenderMale2,
     kGenderFemale2
     } sex2;
     sex2 = kGenderFemale2;
     
     enum
     {
     kGenderMale3,
     kGenderFemale3
     } sex3;
     sex3 = kGenderFemale3;
     */
    
}
// ----------------------------給結構體型別起別名----------------------------


// 1.先定義結構體型別, 再給型別起別名
/*
 struct Person
 {
 int age;
 double height;
 char *name;
 };
 // SPerson == struct Person
 typedef struct Person SPerson;
 */

// 2.定義結構體型別的同時, 給結構體型別起別名
/*
 typedef struct Person
 {
 int age;
 double height;
 char *name;
 } SPerson;
 */

// 3.定義結構體型別的同時, 給結構體型別起別名, 並且省略掉原有型別的名稱

 typedef struct
 {
 int age;
 double height;
 char *name;
 } SPerson;
void test2()
{
    /*
     // 給構造型別起別名
     struct Person
     {
     int age;
     double height;
     char *name;
     };
     */
//    struct Person sp0;
    SPerson sp;
    SPerson sp1;
    SPerson sp2;
    SPerson sp3;
    SPerson sp4;
    /*
     結構體變數的定義方式
     1.先定義型別再定義變數
     2.定義型別的同時定義變數
     3.定義型別的同時定義變數, 並且省略型別名稱
     */
}

// ----------------------------給基本資料型別起別名----------------------------
// Integer == int
typedef int Integer;
typedef Integer myInt;
// int float doulbe char
void test1()
{
    int num = 10;
    printf("num = %i\n", num);
    
    Integer age = 30;
    printf("age = %i\n", age);
    
    myInt score = 99;
    printf("score = %i\n", score);
}

// 一般情況下如果要給資料型別起一個名稱建議用typedef, 不要用define

最後的建議如果想了解透徹c語言還是看看程式碼比較好。

相關文章