<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      指針詳解3

      運行環境以Dev-C++、Visual Studio 2022、MacOS的命令行和Xcode為主

      1.字符指針變量

      // 代碼1:將字符變量的地址賦值給字符指針變量
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char ch = 'w';
          char *pc = &ch;
          *pc = 'b';
          printf("%c\n", *pc);
      
          return 0;
      }
      
      // 代碼2:將字符串賦值給字符指針變量,實際上字符串"abcdef"并沒有存放在字符指針pstr中
      // 本質上是將字符串"abcdef"首字符'a'的地址存到了指針變量pstr中
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          const char *pstr = "abcdef";
          printf("%s\n", pstr);
          return 0;
      }
      
      // 代碼3:對比分析字符串常量和字符串數組。str3和str4指向的是同一個常量字符串,C語言會把常量字符串存儲到單獨的一個內存區域
      // 當幾個指針指向同一個字符串時,它們會指向同一塊內存。但用相同的字符串常量初始化不同的數組時,會開辟出不同的內存塊
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char str1[] = "hello world";
          char str2[] = "hello world";
          const char* str3 = "hello world";
          const char* str4 = "hello world";
      
          if (str1 == str2) {
              printf("str1 and str2 are same\n");
          }
          else {
              printf("str1 and str2 are not same\n");
          }
              
          if (str3 == str4) {
              printf("str3 and str4 are same\n");
          }
          else {
              printf("str3 and str4 are not same\n");
          }
          
          return 0;
      }
      

      image

      2.數組指針變量

      • 2.1 定義和指向原理

        • 整型指針變量存放整型變量的地址,指向整型數據,如int *p_int;;浮點型指針變量存放浮點型變量的地址,指向浮點型數據,如float *pf;

        • 數組指針變量存放數組的地址,是能夠指向數組的指針變量,如int (*p_arr)[10];

          • p_arr先和*結合,說明p_arr是一個指針,指針指向的是一個大小為 10 個整型的數組

          • p_arr是一個指針,指向一個數組,稱為數組指針

          • []的優先級高于*,所以必須加上()來保證p_arr先和*結合

      • 2.2 數組指針的初始化

        • 前面的知識中詳細分析了數組名、數組首元素的地址、數組的地址間的區別和聯系。&數組名便獲得了數組的地址。若要存放該地址,要用到數組指針變量
        int arr[10] = {0};
        int (*p)[10] = &arr;
        // 調試后查看&arr和p的類型完全一致
        
        int        (*p)        [10]        =        &arr;
         |           |           |
         |           |           |
         |           |          p指向數組的元素個數
         |          p是數組指針變量名
        p指向的數組元素的類型
        

        image

      3.二維數組傳參的本質

      • 3.1 數組形式的形參

        • 這是在第 6 章中二維數組作為形參的主要形式

        • 實參是二維數組,形參也寫成二維數組的形式

        #include <stdio.h>
        
        void print_arr(int arr[3][5], int r, int c) {    // int arr[][5] 也可以
            int i = 0;
            for (i = 0; i < r; i++) {
                int j = 0;
                for (j = 0; j < c; j++) {
                    printf("%d ", arr[i][j]);
                }
                printf("\n");
            }
        }
        
        int main(int argc, const char * argv[]) {
            int arr[3][5] = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}};
            print_arr(arr, 3, 5);
        
            return 0;
        }
        
      • 3.2 數組指針形式的形參

        • 二維數組是一維數組的集合,是由一維數組組成的數組,它的首元素就是第一行,也是個一維數組

        • 根據數組名是數組首元素地址這個規則,二維數組的數組名表示第一行,是一維數組的地址

        • 第一行的一維數組的類型為int [5],所以第一行的地址類型為數組指針類型int (*)[5]

        • 二維數組傳參本質上也是傳遞了地址,且是第一行這個一維數組的地址

        #include <stdio.h>
        
        void print_arr(int (*p)[5], int r, int c) {
            int i = 0, j = 0;
            for (i = 0; i < r; i++) {
                for (j = 0; j < c; j++) {
                    printf("%d ", *(*(p + i) + j));
                    // printf("%d ", p[i][j]);
                    // printf("%d ", (*(p + i))[j]);
                }
            }
        }
        
        int main(int argc, const char * argv[]) {
            int arr[3][5] = {{1, 2, 3, 4, 5}, {2, 3, 4, 5, 6}, {3, 4, 5, 6, 7}};
            print_arr(arr, 3, 5);
        
            return 0;
        }  
        

      4.函數指針變量

      • 4.1 定義和指向原理

        • 數組名表示數組首元素的地址,通過它可以定位到數組元素。類似地,函數名表示函數的地址,也可以通過&函數名的方式獲得函數的地址
        #include <stdio.h>
        
        void test(void) {
            printf("test_function\n");
        }
        
        int main(int argc, const char * argv[]) {
            printf("test:  %p\n", test);
            printf("&test: %p\n", &test);
            
            return 0;
        }
        

        image

        • 既然函數名就是函數的地址,就可以用指針變量存儲該地址,這樣的指針變量稱為函數指針,它的寫法和數組指針類似
        void test(void) {
            printf("test_function\n");
        }
        
        void (*pf1)(void) = &test;
        void (*pf2)(void) = test;
        
        int Add(int x, int y) {
            return x + y;
        }
        
        int (*pf3)(int, int) = Add;
        int (*pf4)(int x, int y) = &Add;    // 加不加x和y都可以
        
        int        (*pf3)    (int x, int y)    =        &arr;
         |           |             |
         |           |             |
         |           |            pf3指向函數的參數類型和參數數量
         |          函數指針變量名
        pf3指向函數的返回類型
        
      • 4.2 函數指針的使用

        • 通過函數指針調用指針指向的函數

        • 由于&函數名函數名的打印結果一致,所以通過函數指針調用函數時函數指針旁加不加解引用操作符*均可

        #include <stdio.h>
        
        int Add(int x, int y) {
            return x + y;
        }
        
        int main(int argc, const char * argv[]) {
            int (*pf3)(int, int) = Add;
            printf("%d\n", (*pf3)(2, 3));    // 打印結果:5
            printf("%d\n", pf3(4, 5));        // 打印結果:9
            
            return 0;
        }
        
      • 4.3 typedef關鍵字

        • typedef用于類型重命名,可以將復雜的類型簡單化
        // 1.普通變量類型重命名
        typedef unsigned int uint;
        // 將unsigned int重命名為uint
        
        // 2.指針變量類型重命名
        typedef int * ptr_t;
        // 將int * 重命名為 ptr_t
        
        // 3.數組指針重命名
        typedef int(*parr_t) [5];
        // 將int (*)[5] 重命名為parr_t,新類型名必須在 * 的右邊
        
        // 4.函數指針重命名
        typedef void (*pf_t)(int);
        // 將void (*) (int) 重命名為pf_t,新類型名必須在 * 的右邊
        
        // 5.分析以下代碼
        (*(void (*)())0)();
        // 是一次函數調用,調用0地址處存放的那個函數。0地址處的函數沒有參數,返回類型為void
        
        // 6.分析以下代碼并用typedef重命名
        void (*signal(int, void(*)(int)))(int);
        // 是一次函數聲明,函數名為signal,參數有兩個,類型分別是整型int和函數指針void(*)(int)
        // signal函數的返回值也是一個函數指針,類型為 void (*) (int),它指向的函數參數是,范回類型為void
        
        typedef void (*pf_t) (int)
        pf_t signal(int, pf_t)
        

      5.函數指針數組

      • 5.1 定義和指向原理

        • 將函數的地址存入一個數組中,該數組稱為函數指針數組
        int (*parr1[3])();
        // parr1先和[]結合,說明parr1是數組,數組的內容是int (*)()類型的函數指針
        
      • 5.2 轉移表

        • 使用一般的方法編寫程序實現一個計算器
        #include <stdio.h>
        
        int Add(int x, int y) {
            return x + y;
        }
        
        int Sub(int x, int y) {
            return x - y;
        }
        
        int Mul(int x, int y) {
            return x * y;
        }
        
        int Div(int x, int y) {
            return x / y;
        }
        
        void menu(void) {
            printf("**********************\n");
            printf("**** 1.Add  2.Sub ****\n");
            printf("**** 3.Mul  4.Div ****\n");
            printf("******* 0. Exit ******\n");
            printf("**********************\n");
        }
        
        int main(int argc, const char * argv[]) {
            int x = 0, y = 0;
            int input = 0;
            int ret = 0;
            
            do {
                menu();
                printf("請輸入你的選擇:");
                scanf("%d", &input);
                
                switch (input) {
                    case 1:
                        printf("請輸入兩個數:");
                        scanf("%d %d", &x, &y);
                        ret = Add(x, y);
                        printf("ret = %d\n", ret);
                        break;
                    case 2:
                        printf("請輸入兩個數:");
                        scanf("%d %d", &x, &y);
                        ret = Sub(x, y);
                        printf("ret = %d\n", ret);
                        break;
                    case 3:
                        printf("請輸入兩個數:");
                        scanf("%d %d", &x, &y);
                        ret = Mul(x, y);
                        printf("ret = %d\n", ret);
                        break;
                    case 4:
                        printf("請輸入兩個數:");
                        scanf("%d %d", &x, &y);
                        ret = Div(x, y);
                        printf("ret = %d\n", ret);
                        break;
                    case 0:
                        printf("退出...\n");
                        break;
                    default:
                        printf("輸入錯誤,重新輸入!\n");
                        break;
                }
                
            } while (input);
        
            return 0;
        }
        

        image

        • 使用函數指針數組編寫程序實現一個計算器
        // 代碼1:通過函數指針數組實現
        #include <stdio.h>
        
        void menu(void) {
            printf("**********************\n");
            printf("**** 1.Add  2.Sub ****\n");
            printf("**** 3.Mul  4.Div ****\n");
            printf("******* 0. Exit ******\n");
            printf("**********************\n");
        }
        
        int Add(int x, int y) {
            return x + y;
        }
        
        int Sub(int x, int y) {
            return x - y;
        }
        
        int Mul(int x, int y) {
            return x * y;
        }
        
        int Div(int x, int y) {
            return x / y;
        }
        
        
        int main(int argc, const char * argv[]) {
            int x = 0, y = 0;
            int input = 0;
            int ret = 0;
            int (*pf[5])(int, int) = {0, Add, Sub, Mul, Div};
            
            do {
                menu();
                printf("請輸入你的選擇:");
                scanf("%d", &input);
                
                if (input >= 1 && input <= 4) {
                    printf("請輸入兩個整數:");
                    scanf("%d %d", &x, &y);
                    ret = pf[input](x, y);
                    printf("ret = %d\n", ret);
                }
                else if (input == 0) {
                    printf("退出...\n");
                }
                else {
                    printf("輸入錯誤,重新輸入!\n");
                }
            } while (input);
        
            return 0;
        }
        
        
        
        // 代碼2:通過函數指針實現
        #include <stdio.h>
        
        void menu(void) {
            printf("**********************\n");
            printf("**** 1.Add  2.Sub ****\n");
            printf("**** 3.Mul  4.Div ****\n");
            printf("******* 0. Exit ******\n");
            printf("**********************\n");
        }
        
        int Add(int x, int y) {
            return x + y;
        }
        
        int Sub(int x, int y) {
            return x - y;
        }
        
        int Mul(int x, int y) {
            return x * y;
        }
        
        int Div(int x, int y) {
            return x / y;
        }
        
        void calc(int (*pf)(int, int)) {
            int x = 0, y = 0;
            int ret = 0;
            
            printf("輸入兩個整數:");
            scanf("%d %d", &x, &y);
            ret = pf(x, y);
            printf("ret = %d\n", ret);
        }
        
        int main(int argc, const char * argv[]) {
            int input = 0;
        
            do {
                menu();
                printf("請輸入你的選擇:");
                scanf("%d", &input);
        
                switch (input) {
                    case 1:
                        calc(Add);
                        break;
                    case 2:
                        calc(Sub);
                        break;
                    case 3:
                        calc(Mul);
                        break;
                    case 4:
                        calc(Div);
                        break;
                    case 0:
                        printf("退出...\n");
                        break;
                    default:
                        printf("輸入錯誤,重新輸入!\n");
                        break;
                }
        
            } while (input);
        
            return 0;
        }
        

      6.回調函數

      • 6.1 定義和實例對比

        • 回調函數就是通過函數指針調用的函數。如果將函數指針(地址)作為參數傳遞給另一個函數,當這個指針被用來調用其所指向的函數時,被調用的函數就是回調函數

        • 回調函數不是由該函數的實現方法直接調用,而是在特定的事件或條件發生時由另外的一方調用,用于對該事件或條件進行響應

        • 在 5.2 節實現計算器的案例中,最開始使用的是普通方法,在switch結構中輸入輸出操作重復出現,代碼有較多冗余。這些代碼只有調用函數的邏輯略有區別,因此將調用函數的地址以實參的形式傳遞給calc()函數,它的參數是一個函數指針,該指針指向什么函數就調用什么函數。這里使用的就是回調函數的功能

        image

      • 6.2 qsort函數

        • 1.函數原型
        // 對base指向數組的num個元素進行排序,每個元素的大小為bytes字節,排序規則由compar函數決定
        // 此函數使用的排序算法通過調用指定的compar函數來比較元素對,調用時會將指向這兩個元素的指針作為參數傳遞給compar函數
        // 該函數無返回值,但會修改base所指向數組的內容,按照compar函數定義的規則對元素重新排序
        // 對于值相等的元素,它們的最終順序是未定義的(即不保證穩定排序)
         void qsort(void* base,   // 指向待排序數組的第1個元素的指針
                    size_t num,   // base指向數組中的元素個數
                    size_t size,  // base指向數組中各個元素的大小,單位是字節
                    int (*compare)(const void *, const void *)   // 函數指針,傳遞函數的地址
                    );
        

        image

        • 2.使用qsort()函數排序整型數據
        
        
        #include <stdio.h>
        #include <string.h>
        
        //int cmp_int(const void *p1, const void *p2) {
        //    if (*(int *)p1 > *(int *)p2) {
        //        return 1;
        //    }
        //    else if(*(int *)p1 < *(int *)p2) {
        //        return -1;
        //    }
        //    else {
        //        return 0;
        //    }
        //}
        
        int cmp_int(const void *p1, const void *p2) {
            return *(int *)p1 - *(int *)p2;
        }
        
        void print_arr(int arr[], int sz) {
            int i = 0;
            for (i = 0; i < sz; i++) {
                printf("%d ", arr[i]);
            }
            printf("\n");
        }
        
        void test1(void) {
            int arr[] = {2, 4, 6, 8, 0, 5, 3, 7, 9};
            int sz = sizeof(arr) / sizeof(arr[0]);
            qsort(arr, sz, sizeof(int), cmp_int);
            print_arr(arr, sz);
        }
        
        int main(int argc, const char * argv[]) {
            // insert code here...
            test1();
        
            return 0;
        }
        

        image

        • 3.使用qsort()函數排序結構數據
        #include <stdio.h>
        #include <string.h>
        
        struct Stu {
            char name[20];
            int age;
        };
        
        void print_stu(struct Stu arr[], int sz) {
            int i = 0;
            for (i = 0; i < sz; i++) {
                printf("%s--%d\n", arr[i].name, arr[i].age);
            }
            printf("\n");
        }
        
        // 按照年齡排序
        int cmp_stu_by_age(const void *p1, const void *p2) {
            return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
        }
        
        // 測試qsort函數排序結構體數據,按照名字比較兩個結構體數據
        // 名字是字符串,字符串比較時使用strcmp函數
        int cmp_stu_by_name(const void *p1, const void *p2) {
            // ->的優先級1高于強制類型轉換2,所以要將轉換后的指針整體使用->
            return strcmp(((struct Stu *)p1)->name, ((struct Stu*)p2)->name);
        }
        
        void test2(void) {
            // 按姓名排序時需要將結構體數組中的姓名寫成英文,寫中文的話可能會因為編碼導致預期跟實際結果不一致
            struct Stu arr[] = {{"zhangsan", 34}, {"lisi", 24}, {"wangwu", 40} };
            int sz = sizeof(arr) / sizeof(arr[0]);
            qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
            print_stu(arr, sz);
        }
        
        void test3(void) {
            struct Stu arr[] = {{"張三", 34}, {"李四", 24}, {"王五", 40} };
            int sz = sizeof(arr) / sizeof(arr[0]);
            qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
            print_stu(arr, sz);
        }
        
        int main(int argc, const char * argv[]) {
            // insert code here...
            printf("sorted by name:\n");
            test2();
            printf("sorted by age:\n");
            test3();
            return 0;
        }
        

        image

        • 4.使用冒泡排序模擬實現qsort()函數
        #include <stdio.h>
        #include <string.h>
        
        struct Stu {
            char name[20];
            int age;
        };
        
        void swap(char *buff1, char *buff2, size_t width) {
            int i = 0;
            char temp = 0;
            for (i = 0; i < width; i++) {
                temp = *buff1;
                *buff1 = *buff2;
                *buff2 = temp;
                
                buff1++;
                buff2++;
            }
        }
        
        void bubble_sort(void *base, size_t sz, size_t width, int (*cmp)(const void *p1, const void *p2)) {
            int i = 0, j = 0;
            for (i = 0; i < sz - 1; i++) {
                for (j = 0; j < sz - 1 - i; j++) {
                    if(cmp((char *)base + j * width, (char *)base + (j + 1) * width) > 0) {
                        swap((char *)base + j * width, (char *)base + (j + 1) * width, width);
                    }
                }
            }
        }
        
        int cmp_int(const void *p1, const void *p2) {
            return *(int *)p1 - *(int *)p2;
        }
        
        int cmp_stu_by_name(const void *p1, const void *p2) {
            return strcmp(((struct Stu *)p1)->name, ((struct Stu*)p2)->name);
        }
        
        int cmp_stu_by_age(const void *p1, const void *p2) {
            return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age;
        }
        
        void print_arr(int arr[], int sz) {
            int i = 0;
            for (i = 0; i < sz; i++) {
                printf("%d ", arr[i]);
            }
            printf("\n");
        }
        
        void print_stu(struct Stu arr[], int sz) {
            int i = 0;
            for (i = 0; i < sz; i++) {
                printf("%s--%d\n", arr[i].name, arr[i].age);
            }
            printf("\n");
        }
        
        void test1(void) {
            int arr[] = {2, 4, 6, 8, 0, 5, 3, 7, 9};
            int sz = sizeof(arr) / sizeof(arr[0]);
            bubble_sort(arr, sz, sizeof(int), cmp_int);
            print_arr(arr, sz);
        }
        
        void test2(void) {
            struct Stu arr[] = {{"zhangsan", 34}, {"lisi", 24}, {"wangwu", 40} };
            int sz = sizeof(arr) / sizeof(arr[0]);
            bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
            print_stu(arr, sz);
        }
        
        void test3(void) {
            struct Stu arr[] = {{"張三", 34}, {"李四", 24}, {"王五", 40} };
            int sz = sizeof(arr) / sizeof(arr[0]);
            bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
            print_stu(arr, sz);
        }
        
        int main(int argc, const char * argv[]) {
            // insert code here...
        //    test1();
        //    test2();
            test3();
            return 0;
        }
        
        
      posted @ 2025-08-16 09:47  pycoder_666  閱讀(17)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 粉嫩av一区二区三区蜜臀 | 无码国产精品一区二区免费虚拟vr| 在线观看国产成人av天堂| 亚洲天堂伊人久久a成人| 伊人久久大香线蕉av一区二区| 亚洲精品成人久久av| 亚洲最大成人在线播放| 国产区图片区小说区亚洲区| 欧美巨大巨粗黑人性aaaaaa| 深州市| 国产中年熟女高潮大集合| 亚洲中文字幕在线二页| 越南女子杂交内射bbwxz| 久久99日本免费国产精品| 日韩在线观看中文字幕| 欧美日韩国产va在线观看免费| 久久国产免费观看精品3| 国产对白老熟女正在播放| 成人爽A毛片在线视频淮北| 龙川县| 兔费看少妇性l交大片免费| 国产综合av一区二区三区| 成人看的污污超级黄网站免费| 国产成人av一区二区三区不卡| 国产尤物精品自在拍视频首页| 国产超碰人人做人人爰| 欧洲成人在线观看| 国产美女69视频免费观看| 特级做a爰片毛片免费看无码| 日韩精品卡一卡二卡三卡四| 国产卡一卡二卡三免费入口 | 激情综合色综合久久综合| 免费国产一区二区不卡| 99久久婷婷国产综合精品青草漫画| 亚洲中文字幕人妻系列| 丁香五月激情图片| 日本免费观看mv免费版视频网站| 影音先锋亚洲成aⅴ人在| 欧洲免费一区二区三区视频| 国产综合久久久久久鬼色| 中文字幕成人精品久久不卡|