1. 程式人生 > >char ** 與char * a[ ] 區別

char ** 與char * a[ ] 區別

 先看 char  *a [ ] ;

            由於[ ] 的優先順序高於* 所以a先和 [ ]結合,他還是一個數組,陣列中的元素才是char * ,前面講到char * 是一個變數,儲存的地址。。

            所以 char *a[ ] = {"China","French","America","German"};

            同過這句可以看到, 陣列中的元素是字串,那麼sizeof(a) 是多少呢,有人會想到是五個單詞的佔記憶體中的全部位元組數 6+7+8+7 = 28;

            但是其實sizeof(a) = 16;

            為什麼,前面已經說到, 字串常量的本質是地址,a 陣列中的元素為char * 指標,指標變數佔四個位元組,那麼四個元素就是16個位元組了

            看一下例項:

            #include <stdio.h>

   int main()
   {
    char *a [ ] = {"China","French","America","German"};
    printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]);

    return 0;
   }

可以看到陣列中的四個元素儲存了四個記憶體地址,這四個地址中就代表了四個字串的首地址,而不是字串本身。。。

      因此sizeof(a)當然是16了。。

      注意這四個地址是不連續的,它是編譯器為"China","French","America","German" 分配的記憶體空間的地址, 所以,四個地址沒有關聯。

         #include <stdio.h>

   int main()
   {
   char *a [ ] = {"China","French","America","German"};

           printf("%p %p %p %p\n",a[0],a[1],a[2],a[3]); //陣列元素中儲存的地址
   printf("%p %p %p %p\n",&a[0],&a[1],&a[2],&a[3]);//陣列元素單元本身的地址

   return 0;
   }

 可以看到 0012FF38 0012FF3C 0012FF40 0012FF44,這四個是元素單元所在的地址,每個地址相差四個位元組,這是由於每個元素是一個指標變數佔四個位元組。。。

       char **s;

       char **為二級指標, s儲存一級指標 char *的地址,關於二級指標就在這裡不詳細討論了 ,簡單的說一下二級指標的易錯點。  

       舉例:

       char *a [ ] = {"China","French","America","German"};

       char **s =   a;

       為什麼能把 a賦給s,因為陣列名a代表陣列元素記憶體的單元的首地址,即 a = &a[0] = 0012FF38;

       而 0x12FF38即 a[0]中儲存的又是 00422FB8 ,這個地址, 00422FB8為字串"China"的首地址。

       即 *s = 00422FB8 = "China";

         這樣便可以通過s 操作 a 中的資料

      printf("%s",*s);

      printf("%s",a[0]);

      printf("%s",*a);

      都是一樣的。。。

      但還是要注意,不能a = s,前面已經說到,a 是一個常量。。

      再看一個易錯的點:

      char **s = "hello world";

      這樣是錯誤的,

       因為  s 的型別是 char **  而 "hello world "的型別是 char *

       雖然都是地址, 但是指向的型別不一樣,因此,不能這樣用。,從其本質來分析,"hello world",代表一個地址,比如0x003001,這個地址中的內容是 'h'

  ,為 char 型,而 s 也儲存一個地址 ,這個地址中的內容(*s) 是char * ,是一個指標型別, 所以兩者型別是不一樣的。 。。

  如果是這樣呢?
  char  **s;

       *s = "hello world";

       貌似是合理的,編譯也沒有問題,但是 printf("%s",*s),就會崩潰

       why??

      咱來慢慢推敲一下。。

       printf("%s",*s); 時,首先得有s 儲存的地址,再在這個地址中找到 char *  的地址,即*s;

      舉例:

       s = 0x1000;

      在0x1000所在的記憶體的單元中儲存了"hello world"的地址 0x003001 , *s = 0x003001;

      這樣printf("%s",*s);

      這樣會先找到 0x1000,然後找到0x003001;

      如果直接 char  **s;

      *s = "hello world";

       s 變數中儲存的是一個無效隨機不可用的地址, 誰也不知道它指向哪裡。。。。,*s 操作會崩潰。。

       所以用 char **s 時,要給它分配一個記憶體地址。

      char  **s ;

      s = (char **) malloc(sizeof(char**));

      *s =  "hello world";

      這樣 s 給分配了了一個可用的地址,比如 s = 0x412f;

      然後在 0x412f所在的記憶體中的位置,儲存 "hello world"的值。。

    再如:

    #include  <stdio.h>

   void  buf( char **s)

    {

           *s = "message";

    }

    int main()

     {

        char *s ;

        buf(&s);

        printf("%s\n",s);

     }

    二級指標的簡單用法,說白了,二級指標儲存的是一級指標的地址,它的型別是指標變數,而一級指標儲存的是指向資料所在的記憶體的單元的地址,雖然都是地址,但是型別是不一樣的