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

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

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

      指針詳解4

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

      1.sizeof和strlen的對比

      • 1.1 sizeof

        • sizeof用于計算變量占據內存空間的大小,單位是字節。如果操作數是類型的話,計算的是使用該類型創建的變量所占內存空間的大小

        • sizeof只關注占用內存空間的大小,不在乎內存中存放什么數據

        #include <stdio.h>
        
        int main(int argc, const char * argv[]) {
            int a = 0;
            printf("%zd\n", sizeof(a));
            printf("%zd\n", sizeof a);
            printf("%zd\n", sizeof(int));
            
            return 0;
        }
        

        image

      • 1.2 strlen

        • strlen是C語言庫函數,功能是求字符串長度,函數原型為size_t strlen(const char *str);

        • 計算從函數的參數str指向的地址開始往后,直到\0之前的字符個數

        • strlen函數會一直向后找\0字符,直到找到為止,因此可能存在越界查找

        #include <stdio.h>
        
        int main(int argc, const char * argv[]) {
            char arr1[3] = { 'a', 'b', 'c' };
            char arr2[] = "abc";
        
            printf("%zd\n", strlen(arr1));
            printf("%zd\n", strlen(arr2));
        
            printf("%zd\n", sizeof(arr1));
            printf("%zd\n", sizeof(arr2));  
        
            int arr[] = { 1, 2, 3, 4, 5, 0};
            printf("%zd\n", strlen(arr));    // 1
            // 參考數組在內存中的分布,01即00000001,是1個字節,后面的0會被看成'\0'
            return 0;
        }
        

        image

        image

        sizeof strlen
        1.sizeof是操作符 1.strlen是庫函數,使用前需要包含頭文件string.h
        2.sizeof計算操作數所占內存的大小,單位是字節 2.strlen用于求字符串長度,統計\0之前的字符個數
        3.不關注內存中存放什么數據 3.關注內存中是否有\0,如果沒有\0,就會持續向后找,可能會越界

      2.數組和指針題目解析

      • 2.1 數組名和意義

        • sizeof(數組名)中的數組名表示整個數組,計算的是整個數組的大小

        • &數組名中的數組名表示整個數組,取出的是整個數組的地址

        • 除以上兩種情況外,所有的數組名都表示首元素的地址

      • 2.2 一維數組

      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          int a[] = {1, 2, 3, 4};
          printf("%zd\n", sizeof(a)); // 16
          // 數組名單獨放在sizeof內部,a表示整個數組,計算整個數組占用內存的大小,即4B*4=16B
      
          printf("%zd\n", sizeof(a + 0)); // 4或8
          // a是數組名,未單獨放在sizeof內部,表示數組首元素的地址,加上0依然是首元素的地址,計算該地址占用內存的大小
      
          printf("%zd\n", sizeof(*a));    // 4   *(a + 0) = a[0]
          // a表示數組首元素的地址,解引用后取到首元素,int型長度為4B
      
          printf("%zd\n", sizeof(a + 1)); // 4或8
          // a表示數組首元素的地址,a+1表示第2個元素的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(a[1]));  // 4 計算第2個元素的長度
      
          printf("%zd\n", sizeof(&a));    // 4或8
          // a與&放一塊,這里的a表示整個數組,&a就是整個數組的地址,地址占據內存長度為4B或8B    
      
          printf("%zd\n", sizeof(*&a));   // 16
          // 思路1:*&a的*和&抵消,就是sizeof(a)
          // 思路2:&a是數組的地址,類型為int (*)[4],*&a就是訪問這個數組
      
          printf("%zd\n", sizeof(&a + 1));    // 4或8
          // &a是數組的地址,&a+1是跳過整個數組后新位置的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&a[0]));     // 4或8
          // 第1個元素的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&a[0] + 1)); // 4或8
          // 第2個元素的地址,地址占據內存長度為4B或8B
      
          return 0;
      }
      

      image

      • 2.3 字符數組
      // 代碼1
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char arr[] = { 'a','b','c','d','e','f' };
          
          printf("%zd\n", sizeof(arr));    // 6
          // arr單獨放在sizeof內部,表示整個數組,占據內存6B
      
          printf("%zd\n", sizeof(arr + 0));    // 4或8
          // arr表示數組首元素的地址,加0依然是首元素地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(*arr));    // 1
          // arr未單獨放在sizeof內部,它表示數組首元素的地址,解引用取到了首元素,char型占據內存1B
      
          printf("%zd\n", sizeof(arr[1]));    // 1
          // 計算字符'b'占據內存的長度
      
          printf("%zd\n", sizeof(&arr));    // 4或8
          // &arr表示整個數組的地址,地址占據內存長度為4B或8B
        
          printf("%zd\n", sizeof(&arr + 1));    // 4或8
          // &arr表示整個數組的地址,&arr+1表示跳過整個數組后新位置的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&arr[0] + 1));    // 4或8
          // &arr[0] + 1即&arr[1],地址占據內存長度為4B或8B
      
          return 0;
      }
      

      image

      // 代碼2
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char arr[] = { 'a','b','c','d','e','f' };
          printf("%zd\n", strlen(arr));    // 隨機值,字符數組中沒有 '\0'
          printf("%zd\n", strlen(arr + 0));    //隨機值,同上
      
          // printf("%zd\n", strlen(*arr));    // 程序崩潰,無法運行
          // arr是數組名表示首元素的地址,*arr即首元素'a',其值為97
          // 強行將97傳遞給strlen,函數會將97認做地址,然后去訪問內存,但這是非法訪問,程序奔潰
      
          printf("%zd\n", strlen(arr[1]));    // 同上,程序崩潰,無法運行
          // 強行將字符'b'的值98傳遞給strlen,非法訪問
      
          printf("%zd\n", strlen(&arr));    // 隨機值
          // &arr 表示整個數組的地址,在數值上和數組首元素地址相等,由此向后找'\0',但字符數組中沒有 '\0',因此是隨機值
      
          printf("%zd\n", strlen(&arr + 1));    //隨機值
          // &arr表示整個數組的地址,&arr+1表示跳過整個數組后新位置的地址,從它開始向后找'\0'
      
          printf("%zd\n", strlen(&arr[0] + 1));    //隨機值
          // &arr[0] + 1即&arr[1],從第2個數組元素開始往后找'\0',但字符數組中沒有 '\0',因此是隨機值
      
          return 0;
      }
      

      image

      // 代碼3
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char arr[] = "abcdef";    // 字符串末尾存在'\0'
      
          printf("%zd\n", sizeof(arr));    // 7
          // arr單獨放在sizeof內部表示整個數組,占據內存7B
      
          printf("%zd\n", sizeof(arr + 0));    // 4或8
          // arr未單獨放在sizeof內部,它表示數組首元素的地址,加0依然是首元素地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(*arr));    // 1
          // 思路1:arr是首元素的地址,解引用后取到首元素,占據內存1B
          // 思路2:*arr --> *(arr + 0) --> arr[0]
      
          printf("%zd\n", sizeof(arr[1]));    // 1 下標為1的字符,占據內存1B
          
          printf("%zd\n", sizeof(&arr));    // 4或8
          // &arr表示整個數組的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&arr + 1));    // 4或8
          // &arr表示整個數組的地址,&arr+1表示跳過整個數組后新位置的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&arr[0] + 1));    // 4或8
          // 即&arr[1],是一個地址,占據內存長度為4B或8B
          return 0;
      }
      

      image

      // 代碼4
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char arr[] = "abcdef";    // 字符串末尾存在'\0'
      
          printf("%zd\n", strlen(arr));    // 6
          // arr表示首元素的地址,從字符'a'開始往后統計'\0'之前的字符個數,共6個
      
          printf("%zd\n", strlen(arr + 0));    // 6
          // arr與arr+0均表示首元素的地址,從字符'a'開始往后統計'\0'之前的字符個數,共6個
      
          printf("%zd\n", strlen(*arr));    // 程序崩潰
          // *arr --> *(arr+0) --> 'a' --> 97, 97作為地址傳給給了strlen,但該地址不能訪問
          
          printf("%zd\n", strlen(arr[1]));    // 程序崩潰,理由同上
      
          printf("%zd\n", strlen(&arr));    // 6
          // &arr表示整個數組的地址,與數組首元素的地址指向同一個位置,從字符'a'開始往后統計'\0'之前的字符個數,共6個
      
          printf("%zd\n", strlen(&arr + 1));    // 隨機值
          // &arr表示整個數組的地址,&arr+1表示跳過整個數組后新位置的地址,此處存儲內容未知,不知道'\0'在何處,因此結果不確定
      
          printf("%zd\n", strlen(&arr[0] + 1));    // 5
          // &arr[0] + 1 即 &arr[1],從字符'b'開始往后統計'\0'之前的字符個數,共5個
          return 0;
      }
      

      image

      // 代碼5
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char *p = "abcdef";    // p指向字符串字面量的第1個字符
      
          printf("%zd\n", sizeof(p));    // 4或8
          // p是指針變量,即地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(p + 1));    // 4或8
          // p是指針變量,p+1指向'b',地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(*p));    // 1
          // *p --> *(p+0) --> p[0] --> 'a',字符型變量占據內存1B
      
          printf("%zd\n", sizeof(p[0]));    // 1 同上
      
          printf("%zd\n", sizeof(&p));    // 4或8
          // p是指針變量,&p是指針變量的地址,即地址的地址,也是二級指針char **,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&p + 1));    // 4或8
          // &p+1也是地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(&p[0] + 1));    // 4或8
          // &p[0] + 1即p+1,地址占據內存長度為4B或8B
      
          return 0;
      }
      

      image

      // 代碼6
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char* p = "abcdef";    // p指向字符串字面量的第1個字符
      
          printf("%zd\n", strlen(p));    // 6
          // 從'a'開始計算'\0'之前的字符個數
      
          printf("%zd\n", strlen(p + 1));    // 5
          // 從'b'開始計算'\0'之前的字符個數
      
          printf("%zd\n", strlen(*p));    // 程序崩潰
          // *p --> *(p+0) --> p[0] --> 'a' --> 97 將97作為地址傳給strlen,非法訪問
      
          //printf("%zd\n", strlen(p[0]));    // 程序崩潰,同上
      
          printf("%zd\n", strlen(&p));    // 隨機值
          // &p是指針變量的地址,即地址的地址,此處存儲內容和'\0'的位置均未知
      
          printf("%zd\n", strlen(&p + 1));    // 隨機值,同上
          
          printf("%zd\n", strlen(&p[0] + 1));    // 5
          // &p[0] + 1即p + 1,從'b'開始計算'\0'之前的字符個數
      
          return 0;
      }
      

      image

      • 2.4 二維數組
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          int a[3][4] = { 0 };
      
          printf("%zd\n", sizeof(a));    // 48
          // a單獨放在sizeof內部表示整個數組,求整個數組占據內存的大小,4B*12=48B
      
          printf("%zd\n", sizeof(a[0][0]));    // 4
          // a[0][0]即第1行第1列元素0,整型占據內存4B
      
          printf("%zd\n", sizeof(a[0]));    // 16
          // a[0]是第1行的數組名,單獨放在sizeof內部表示整個第1行,共4B*4=16B
      
          printf("%zd\n", sizeof(a[0] + 1));    // 4或8
          // a[0]是第1行的數組名,未單獨放在sizeof內部,表示&a[0][0],加1后即&a[0][1],地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(*(a[0] + 1)));    // 4
          // a[0] + 1即&a[0][1],解引用后為a[0][1],整型占據內存4B
      
          printf("%zd\n", sizeof(a + 1));    // 4或8
          // a是數組名,未單獨放在sizeof內部,表示首元素的地址,即第1行的地址。加1后表示第2行的地址,地址占據內存長度為4B或8B
          printf("%zd\n", sizeof(*(a + 1)));    // 16
          // a+1即第2行的地址,解引用后取到了第2行,4B*4=16B
      
          printf("%zd\n", sizeof(&a[0] + 1));    // 4或8 第2行的地址
          // a[0]是第1行的數組名,&a[0]表示第1行數組的地址,加1后是第2行的地址,地址占據內存長度為4B或8B
      
          printf("%zd\n", sizeof(*(&a[0] + 1)));    // 16
          // &a[0] + 1即第2行的地址,解引用后取到了第2行,4B*4=16B
      
          printf("%zd\n", sizeof(*a));    // 16
          // a是數組名,未單獨放在sizeof內部,表示數組首元素的地址,即第1行的地址。解引用后取到了第1行,4B*4=16B
      
          printf("%zd\n", sizeof(a[3]));    // 16
          // a[3]即行標為3的整行的地址,越界,但sizeof內部的表達式不會真實計算,4B*4=16B
      
          return 0;
      }
      

      image

      3.指針運算題目解析

      • 3.1 分析以下程序的運行結果
      // &a + 1的類型是數組指針int (*)[5],代碼將其強制轉換為整形指針int *
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          int a[5] = { 1, 2, 3, 4, 5 };
          int* ptr = (int*)(&a + 1);
          printf("%d,%d", *(a + 1), *(ptr - 1));    // 打印結果:2,5
          return 0;
      }
      

      image

      • 3.2 在x86環境下,假設結構體的大小是20B,分析以下程序的輸出結果
      #include <stdio.h>
      
      struct Test {
          int Num;
          char* pcName;
          short sDate;
          char cha[2];
          short sBa[4];
      } * p = (struct Test*)0x100000;
      // 將0x100000地址強制轉為結構體指針變量p
      
      
      int main(int argc, const char * argv[]) {
          // p指向了結構體,跳過1個單位即20B的結構體空間,以十六進制表示20為14
          // x86環境意為32bit的地址總線,0x00100000 + 0x00000014 = 0x00100014
          printf("%p\n", p + 0x1);
          
          // 將p強制轉為無符號長整型,這樣0x100000不再表示地址,而是普通整數
          // 整數加1即數值加1,0x0010000 + 0x00000001 = 0x00100001
          printf("%p\n", (unsigned long)p + 0x1);
      
          // 將p從結構體指針強制轉換為無符號整型指針,0x100000依然是地址
          // 整型指針加1即跳過4B,0x00100000 + 0x00000004 = 0x00100004
          printf("%p\n", (unsigned int*)p + 0x1);
      
          return 0;
      }
      

      image

      • 3.3 分析以下程序的運行結果
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          // 數組元素是逗號表達式,先簡化為 {1, 3, 5, 0, 0, 0}
          int a[3][2] = { (0, 1), (2, 3), (4, 5) };
          int *p = NULL;
      
          // a[0]是第1行數組的數組名,指向一維數組的第1個元素
          p = a[0];
          printf("%d", p[0]);    // 打印結果:1
      
          return 0;
      }
      

      image

      • 3.4 在x86環境下,分析以下程序的輸出結果
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          int a[5][5] = {0};
          int (*p)[4] = {NULL};
      
          // a是二維數組的數組名,表示數組首元素的地址,即第1行的地址,是數組指針類型 int (*)[5]
          p = a;    // 兩者類型不一致,會有警告
      
          // 由指向圖可知兩數組元素存儲位置間隔4個,且后方地址更大,以十進制數打印時結果為-4
          // 以地址打印時,會打印-4的補碼,地址沒有負數,按照源碼、反碼和補碼的運算規則得到0xfffffffc
          //  -4  10000000 00000000 00000000 00000100
          //      11111111 11111111 11111111 11111100
          //      ff       ff       ff       fc
          printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
          
          return 0;
      }
      

      image

      image

      • 3.5 分析以下程序的運行結果
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
          
          // &aa表示整個數組的地址,加1后指向了整個數組末尾,并強制轉為整型指針
          int* ptr1 = (int*)(&aa + 1);
      
          // aa表示數組首元素(第1行)的地址,加1后為第2行的地址,解引用后取到了第2行,隱式轉換成第2行首元素的地址
          int* ptr2 = (int*)(*(aa + 1));
          printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));    // 打印結果:10,5
          return 0;
      }
      

      image

      • 3.6 分析以下程序的執行結果
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          // a是字符指針數組,其每個元素是字符指針(地址),它各指向了3個字符串
          char* a[] = { "work", "at", "alibaba" };
      
          // pa是二級指針,它指向了字符數組a中第一個元素,即work中'w'的首地址
          char** pa = a;
      
          // pa原來的指向失效,重新指向了at中'a'的首地址
          pa++;
          printf("%s\n", *pa);    // 打印結果:at
          return 0;
      }
      
      // 圖中的地址均為假設
      

      image

      image

      • 3.7 分析以下程序的執行結果
      #include <stdio.h>
      
      int main(int argc, const char * argv[]) {
          char* c[] = { "ENTER","NEW","POINT","FIRST" };
          char** cp[] = { c + 3,c + 2,c + 1,c };
          char*** cpp = cp;
          
          // cpp存儲的是cp的地址,它指向了cp,也指向了cp[0]。++cpp后新的cpp指向了cp[1]
          // 第1次解引用取到了cp[1]的值,即0xcfe2,這是一個地址,指向了c[2]
          // 第2次解引用取到了c[2]的值,即0x100B,這也是一個地址,指向了POINT,打印一直到'\0'之前的字符
          printf("%s\n", **++cpp);    //打印結果:POINT
      
          // 上文分析cpp指向了cp[1],繼續++cpp后新的cpp指向了cp[2]
          // 第1次解引用取到了cp[2]的值,即0xcfde,這是一個地址,指向了c[1]
          // c[1]的地址自減之后指向c[0],即0xcfda,也是一個地址,指向了c[0]
          // 第2次解應用取到了c[0]的值,即0x1001,這個地址指向了ENTER
          // 最后加3,地址變為0x1004,指向了字符串"ENTER"的字符'E',打印一直到'\0'之前的字符
          printf("%s\n", *-- * ++cpp + 3);  // ER
      
          // *cpp[-2] + 3即*(*(cpp - 2)) + 3,上文分析cpp指向了cp[2],cpp-2指向了cp[0],即0x31f2
          // 第1次解引用取到了0xcfe6,這是一個地址,指向了c[3]
          // 第2次解引用后取到了0x1011,也是一個地址,指向了FIRST
          // 最后加3,地址變為0x1014,指向了字符串"FIRST"的字符'S',打印一直到'\0'之前的字符
          printf("%s\n", *cpp[-2] + 3);  // ST
      
          // cpp[-1][-1] + 1即*(*(cpp - 1) - 1) + 1,上文分析cpp指向了cp[2],cpp-1指向了cp[1],即0x31f6
          // 第1次解引用取到了0xcfe2,這是一個地址,指向了c[2],c[2]的地址再減1是c[1]的地址0xcfde
          // 第1次解引用取到了c[1]的值0x1007,也是一個地址,指向了NEW
          // 最后加1,地址變為0x1008,指向了字符串"NEW"的字符'E',打印一直到'\0'之前的字符
          printf("%s\n", cpp[-1][-1] + 1);  // EW
      
          return 0;
      }
      
      // 圖中的地址均為假設
      

      image

      image

      posted @ 2025-08-21 17:32  pycoder_666  閱讀(27)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 99久久亚洲精品无码毛片| 爆乳女仆高潮在线观看| 一区二区三区av天堂| 国产嫩草精品网亚洲av| 国产av综合一区二区三区| 免费a级毛片18以上观看精品| 石城县| 99久久er这里只有精品18| 偷拍专区一区二区三区| 制服 丝袜 亚洲 中文 综合| 欧美z0zo人禽交另类视频| 极品美女aⅴ在线观看| 男女性高爱潮免费网站| 国产成人精品亚洲午夜麻豆| 精品久久8x国产免费观看| 天天天做夜夜夜做无码| 亚洲欧美牲交| 久久久久久无码午夜精品直播| 九九视频热最新在线视频| 不卡高清AV手机在线观看| 亚洲AV成人片不卡无码| 国产精品三级国产精品高| 久久99国产精品久久99| 色婷婷欧美在线播放内射| 日韩熟女熟妇久久精品综合| 人妻夜夜爽天天爽三区丁香花| 亚洲www永久成人网站| 欧洲中文字幕一区二区| 精品人妻av区乱码| 日韩精品视频一区二区不卡| 欧美色综合天天久久综合精品| 亚洲精品一区二区三区综合| 两个人免费完整高清视频| 亚洲日本va午夜在线电影| 景德镇市| 亚洲第一香蕉视频啪啪爽| 欧美肥老太牲交大战| 噜噜噜噜私人影院| 亚洲男女羞羞无遮挡久久丫| 亚洲区一区二区三区精品| 亚洲国产精品综合久久网络|