1. 程式人生 > 其它 >C/C++程式設計:深入 理解char * ,char ** ,char a[ ] ,char *a[] 的區別

C/C++程式設計:深入 理解char * ,char ** ,char a[ ] ,char *a[] 的區別

技術標籤:# C++

陣列 VS 指標

1 陣列的本質

  • 陣列是多個元素的集合,在記憶體中分佈在地址相連的單元中,所以可以通過其下標訪問不同單元的元素。。

2 指標。

  • 指標也是一種變數,只不過它的記憶體單元中儲存的是一個標識其他位置的地址。。由於地址也是整數,在32位平臺下,指標預設為32位。。
  • 指向的直接意思就是指標變數所儲存的其他的地址單元中所存放的資料型別。
int  * p ;//p 變數儲存的地址所在記憶體單元中的資料型別為整型
float *q;// ........................................浮點型
  • 不論指向的資料型別為那種,指標變數其本身永遠為整型,因為它儲存的地址。

char *

printf("%c\n",*str);//輸出首字元

printf("%s\n",str);//輸出整串字元

printf("%p\n",str);//輸出字串首字元地址

printf("%p\n",&str);//輸出指標str的地址

用首地址就可以輸出字串。

printf("%s",str);
  • 因為C語言中字串常量的本質表示其實是一個地址

為什麼可以把一個字串賦給一個指標變數。。
這不是型別不一致嗎???

char  *s ;
s = "China"
;
  • 因為C語言中字串常量的本質表示其實是一個地址
  • C語言中編譯器會給字串常量分配地址,如果 “China”, 儲存在記憶體中的 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 .
  • s = “China” ,意識是什麼,對了,地址。
  • 其實真正的意義是 s =“China” = 0x3000;
  • 看清楚了吧 ,你把China 看作是字串,但是編譯器把它看作是地址 0x3000,即字串常量的本質表現是代表它的第一個字元的地址
  • s = 0x3000
  • 這樣寫似乎更符合直觀的意思
  • 搞清楚這個問題。。
  • 那麼%s,它的原理其實也是通過字串首地址輸出字串,·printf("%s ", s)·; 傳給它的其實是s所儲存的字串的地址。。。
    #include <stdio.h>

       int main()
       {

         char *s;
         s = "hello";
         printf("%p\n",s);
         return 0;
      }

在這裡插入圖片描述

  • 可以看到 s = 0x00422020 ,這也是"China"的首地址
  • 所以,printf("%s",0x00422020);也是等效的。。

char [] – 字元陣列

  • 字面意思是陣列,陣列中的元素是字元。。確實,這就是它的本質意義。
  • 由於C語言中沒有真正的字串型別,可以通過字元陣列表示字串,因為它的元素地址是連續的,這就足夠了
  • C語言中規定陣列代表陣列所在記憶體位置的首地址,也是 str[0]的地址,即str = &str[0];
 定義了一個有十個元素的陣列,元素型別為字元。
char  str[10]; 

        
 C語言中定義一個變數時可以初始化。
 char  str[10] = {"hello world"};
當編譯器遇到這句時,會把str陣列中從第一個元素把hello world\0 逐個填入。




char  str[10] = "hello";

前面已經說了,str = &str[0] , 也等於 "hello"的首地址。。

所以printf("%s",str); 本質也是 printf("%s", 地址");
  • C語言中操作字串是通過它在記憶體中的儲存單元的首地址進行的,這是字串的終極本質

char * 與 char a[ ]

char  *s;
char  a[ ] ;
  • a代表字串的首地址,而s 這個指標也儲存字串的地址(其實首地址),即第一個字元的地址,這個地址單元中的資料是一個字元,這也與 s 所指向的 char 一致。因此可以s = a;
  • 但是不能 a = s; 因為a的首地址儲存著一個字元,但是s是一個指標(int型別),另外a是一個常量,所以不能修改
int main(void)
{
    char  a [ ] = "hello";
    char *s =a;

    for(int i= 0; i < strlen(a) ; i++)
        printf("%c", s[i]);

    printf("\n");

    for(int i= 0; i < strlen(a) ; i++)
        printf("%c", a[i]);

    printf("\n");

    printf("%s", s);

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

    printf("\n---------------------\n");
    
    return 0;
}

char * 與 char a[ ] 的本質區別:

  • 當定義 char a[10 ] 時,編譯器會給陣列分配十個單元,每個單元的資料型別為字元。。
  • 而定義 char *s 時, 這是個指標變數,只佔四個位元組,32位,用來儲存一個地址。
  • *char s 只是一個儲存字串首地址的指標變數, char a[ ] 是許多連續的記憶體單元,單元中的元素為char
sizeof(a) = 10; 
sizeof(s)  = 4;  編譯器分配4個位元組32位的空間,這個空間中將要儲存地址
printf("%p",s);  這個表示 s 的單元中所儲存的地址。。
printf("%p",&s); 這個表示變數本身所在記憶體單元地址

char ** 與char * a[ ]

1、 char *a [ ] ;

  • 由於[ ] 的優先順序高於* 所以a先和 [ ]結合,他是一個陣列,陣列中的元素才是char *,char * 是一個用來儲存地址的變數變數
 char *a[ ] = {"China","French","America","German"}
sizeof(a) = 16;      指標變數佔四個位元組,那麼四個元素就是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,這四個是元素單元所在的地址,每個地址相差四個位元組,這是由於每個元素是一個指標變數佔四個位元組

2、 char **s;

  • char **為二級指標, s儲存一級指標 char *的地址