1. 程式人生 > 其它 >[cpp] 字元陣列,字元指標,sizeof,strlen總結

[cpp] 字元陣列,字元指標,sizeof,strlen總結

對於字元陣列與字元指標:

1. 以字串形式出現的,編譯器都會為該字串自動新增一個0作為結束符,如在程式碼中寫"abc",那麼編譯器幫你儲存的是"abc\0".

2. 字串直接量作為字元指標的初始值 

  "hello"是一個字串直接量,編譯器將其作為const char*處理,與之相關聯的記憶體空間位於記憶體的只讀部分,即允許編譯器重用指向等價字串直接量的引用以優化記憶體使用,

即使程式  中使用了字串直接量500次,編譯器在記憶體中也只是建立了一個例項。例如: char *ptr = “hello”; 等價於 const char *ptr = “hello”;

字串直接量"hello"關聯的是隻讀記憶體,如果試圖修改將出錯,例如ptr[1] = ‘a’;是會引起錯誤的。

3. 字串直接量作為基於棧的字元陣列的初始值

    由於基於棧的變數不可能引用其他地方儲存的記憶體,編譯器會負責將字串直接量複製到基於棧的陣列記憶體中。

    例如: char stackArray[] = “hello”;

    做如下修改: stackArray[1] = ‘a’;是真確的。

4. 字元陣列與字元指標

    字元陣列的形式如下,會將字元直接量拷貝到棧上:

          char str[]   = "abc";             // 實際的資料儲存: a b c \0,也就是增加了一個終結符\0

          char str[3] = {'a','b','c'};     // 實際的資料儲存: a b c,並沒有在最後新增終結符

          char str[10] = {'a','b','c'};   // 實際的資料儲存: a b c \0 \0 \0 \0 \0 \0 \0

   字元指標的形式如下:

          char *str = “abc”;               // 實際的資料儲存: a b c \0,也就是增加了一個終結符\0

5. 型別的決定

    1). 陣列的型別是由該陣列所存放元素的型別以及陣列本身的大小決定的

         如char s1[3]和char s2[4],s1的型別就是char[3],s2的型別就是char[4],也就是說盡管s1和s2都是字元陣列,但兩者的型別卻是不同的。

    2). 字串常量的型別可以理解為相應字元常量陣列的型別

         如"abcdef"的型別就可以看成是const char[7],也就是說實際的資料儲存為"abcdef\0"。

    3). 函式引數列表中的以陣列型別書寫的形式引數,編譯器把其解釋為普通的指標型別

         如對於void func(char sa[100],int ia[20],char *p),則sa的型別為char*,ia的型別為int*,p的型別為char*。

對於sizeof與strlen: 

1. sizeof操作符的結果型別是size_t,它在標頭檔案中typedef為unsigned int型別。該型別保證能容納實現所建立的最大物件的位元組大小。

2. sizeof是算符,strlen是函式。

3. sizeof可以用型別做引數,strlen只能用char*做引數,且必須是以''\0''結尾的。

4. 陣列做sizeof的引數不退化,傳遞給strlen就退化為指標了。

5. 大部分編譯程式在編譯的時候就把sizeof計算過了,是型別或是變數的長度這就是sizeof(x)可以用來定義陣列維數的原因。
    char str[20]="0123456789"; // str是編譯期大小已經固定的陣列
     int a=strlen(str); //  a=10; //strlen()在執行起確定,計算的是實際長度
     int b=sizeof(str); //  而b=20; //sizeof()在編譯期確定,str的型別是int[20],計算的是佔據記憶體的大小

6. strlen的結果要在執行的時候才能計算出來,是用來計算字串的實際長度,不是型別佔記憶體的大小。

7. sizeof後如果是型別必須加括弧,如果是變數名可以不加括弧。這是因為sizeof是個操作符不是個函式。
    char c;
    sizeof c;  //變數名可以不加括弧
8. 當適用於一個結構型別或變數, sizeof 返回實際的大小,
    當適用一靜態地空間陣列, sizeof 歸還全部陣列的尺寸。
    sizeof 操作符不能返回動態地被分派了的陣列或外部的陣列的尺寸

sizeof、strlen計算字元陣列、字元指標空間

char str[] = "abc";  實際的資料儲存: a b c \0,也就是增加了一個終結符\0 其型別為char[4]   VS: sizeof(str)=4     strlen(str) = 3
GCC: sizeof(str)=4     strlen(str) = 3
char str[]   = "abc"; 實際的資料儲存: a b c \0,也就是增加了一個終結符\0 其型別為char[4]   VS: sizeof(str)=4     strlen(str) = 3
GCC: sizeof(str)=4     strlen(str) = 3
char str[] = {'a','b','c'}; 實際的資料儲存: a b c,並沒有在最後新增終結符 其型別為char[3]   VS: sizeof(str)=3     strlen(str) = 15
GCC: sizeof(str)=3     strlen(str) = 6
char str[3] = {'a','b','c'}; 實際的資料儲存: a b c,並沒有在最後新增終結符 其型別為char[3]   VS: sizeof(str)=3     strlen(str) = 15
GCC: sizeof(str)=3     strlen(str) = 6
char str[5] = {'a','b','c','d','e'};  實際的資料儲存: a b c d e ,並沒有在最後新增終結符 其型別為char[5]   VS: sizeof(str)=5     strlen(str) = 19
GCC: sizeof(str)=5     strlen(str) = 8
char str[5] = {'a','b','c','d'}; 實際的資料儲存: a b c d \0(預設填充字元\0) 其型別為char[5]   VS: sizeof(str)=5     strlen(str) = 4
GCC: sizeof(str)=5     strlen(str) = 4
char *pstr = "abcde"; 實際的資料儲存: a b c d e \0 pstr的型別為char* sizeof(pstr) = 4 ( 指標的資料儲存空間,4個位元組),strlen(pstr) = 5

總結一下:

1). sizeof的結果是型別的大小,區分型別之後,sizeof的結果也就命了,sizeof的結果是在編譯期決定的,計算的佔據的記憶體大小。

     srelen的結果是在執行期間決定,計算的是實際長度,strlen只能以char*作引數,以\0作為結束符, 以上的例子中,紅色部分的strlen計算是錯誤的,

     因為在str的資料儲存中並沒有 一個\0字元,所以strlen的結果看似有點異常。

2). 注意在計算sizeof的時候:

     char str[] = "abc";  型別為char[4],   sizeof(str) = 4*sizeof(char) = 4.

3). sizeof(express),其中的express在編譯過程中是不會被編譯的,而是被替代型別。

     例如: int a = 1; sizeof(a=2);

     此時的express為a=2,在編譯過程中被替換為sizeof(int),所以在執行完之後,a仍然是等於1.

4). 對函式使用sizeof,在編譯階段會被替換為函式的返回值的型別取代

     例如: int f(){return 0;}  sizeof(f());的結果為4.

             void f(){}            sizeof(f());編譯過程中會出現錯誤,替換之後的sizoeof(void)編譯無法通過.

對於字元陣列與字元指標:

1. 以字串形式出現的,編譯器都會為該字串自動新增一個0作為結束符,如在程式碼中寫"abc",那麼編譯器幫你儲存的是"abc\0".

2. 字串直接量作為字元指標的初始值 

  "hello"是一個字串直接量,編譯器將其作為const char*處理,與之相關聯的記憶體空間位於記憶體的只讀部分,即允許編譯器重用指向等價字串直接量的引用以優化記憶體使用,

即使程式  中使用了字串直接量500次,編譯器在記憶體中也只是建立了一個例項。例如: char *ptr = “hello”; 等價於 const char *ptr = “hello”;

字串直接量"hello"關聯的是隻讀記憶體,如果試圖修改將出錯,例如ptr[1] = ‘a’;是會引起錯誤的。

3. 字串直接量作為基於棧的字元陣列的初始值

    由於基於棧的變數不可能引用其他地方儲存的記憶體,編譯器會負責將字串直接量複製到基於棧的陣列記憶體中。

    例如: char stackArray[] = “hello”;

    做如下修改: stackArray[1] = ‘a’;是真確的。

4. 字元陣列與字元指標

    字元陣列的形式如下,會將字元直接量拷貝到棧上:

          char str[]   = "abc";             // 實際的資料儲存: a b c \0,也就是增加了一個終結符\0

          char str[3] = {'a','b','c'};     // 實際的資料儲存: a b c,並沒有在最後新增終結符

          char str[10] = {'a','b','c'};   // 實際的資料儲存: a b c \0 \0 \0 \0 \0 \0 \0

   字元指標的形式如下:

          char *str = “abc”;               // 實際的資料儲存: a b c \0,也就是增加了一個終結符\0

5. 型別的決定

    1). 陣列的型別是由該陣列所存放元素的型別以及陣列本身的大小決定的

         如char s1[3]和char s2[4],s1的型別就是char[3],s2的型別就是char[4],也就是說盡管s1和s2都是字元陣列,但兩者的型別卻是不同的。

    2). 字串常量的型別可以理解為相應字元常量陣列的型別

         如"abcdef"的型別就可以看成是const char[7],也就是說實際的資料儲存為"abcdef\0"。

    3). 函式引數列表中的以陣列型別書寫的形式引數,編譯器把其解釋為普通的指標型別

         如對於void func(char sa[100],int ia[20],char *p),則sa的型別為char*,ia的型別為int*,p的型別為char*。

對於sizeof與strlen: 

1. sizeof操作符的結果型別是size_t,它在標頭檔案中typedef為unsigned int型別。該型別保證能容納實現所建立的最大物件的位元組大小。

2. sizeof是算符,strlen是函式。

3. sizeof可以用型別做引數,strlen只能用char*做引數,且必須是以''\0''結尾的。

4. 陣列做sizeof的引數不退化,傳遞給strlen就退化為指標了。

5. 大部分編譯程式在編譯的時候就把sizeof計算過了,是型別或是變數的長度這就是sizeof(x)可以用來定義陣列維數的原因。
    char str[20]="0123456789"; // str是編譯期大小已經固定的陣列
     int a=strlen(str); //  a=10; //strlen()在執行起確定,計算的是實際長度
     int b=sizeof(str); //  而b=20; //sizeof()在編譯期確定,str的型別是int[20],計算的是佔據記憶體的大小

6. strlen的結果要在執行的時候才能計算出來,是用來計算字串的實際長度,不是型別佔記憶體的大小。

7. sizeof後如果是型別必須加括弧,如果是變數名可以不加括弧。這是因為sizeof是個操作符不是個函式。
    char c;
    sizeof c;  //變數名可以不加括弧
8. 當適用於一個結構型別或變數, sizeof 返回實際的大小,
    當適用一靜態地空間陣列, sizeof 歸還全部陣列的尺寸。
    sizeof 操作符不能返回動態地被分派了的陣列或外部的陣列的尺寸

sizeof、strlen計算字元陣列、字元指標空間

char str[] = "abc";  實際的資料儲存: a b c \0,也就是增加了一個終結符\0 其型別為char[4]   VS: sizeof(str)=4     strlen(str) = 3
GCC: sizeof(str)=4     strlen(str) = 3
char str[]   = "abc"; 實際的資料儲存: a b c \0,也就是增加了一個終結符\0 其型別為char[4]   VS: sizeof(str)=4     strlen(str) = 3
GCC: sizeof(str)=4     strlen(str) = 3
char str[] = {'a','b','c'}; 實際的資料儲存: a b c,並沒有在最後新增終結符 其型別為char[3]   VS: sizeof(str)=3     strlen(str) = 15
GCC: sizeof(str)=3     strlen(str) = 6
char str[3] = {'a','b','c'}; 實際的資料儲存: a b c,並沒有在最後新增終結符 其型別為char[3]   VS: sizeof(str)=3     strlen(str) = 15
GCC: sizeof(str)=3     strlen(str) = 6
char str[5] = {'a','b','c','d','e'};  實際的資料儲存: a b c d e ,並沒有在最後新增終結符 其型別為char[5]   VS: sizeof(str)=5     strlen(str) = 19
GCC: sizeof(str)=5     strlen(str) = 8
char str[5] = {'a','b','c','d'}; 實際的資料儲存: a b c d \0(預設填充字元\0) 其型別為char[5]   VS: sizeof(str)=5     strlen(str) = 4
GCC: sizeof(str)=5     strlen(str) = 4
char *pstr = "abcde"; 實際的資料儲存: a b c d e \0 pstr的型別為char* sizeof(pstr) = 4 ( 指標的資料儲存空間,4個位元組),strlen(pstr) = 5

總結一下:

1). sizeof的結果是型別的大小,區分型別之後,sizeof的結果也就命了,sizeof的結果是在編譯期決定的,計算的佔據的記憶體大小。

     srelen的結果是在執行期間決定,計算的是實際長度,strlen只能以char*作引數,以\0作為結束符, 以上的例子中,紅色部分的strlen計算是錯誤的,

     因為在str的資料儲存中並沒有 一個\0字元,所以strlen的結果看似有點異常。

2). 注意在計算sizeof的時候:

     char str[] = "abc";  型別為char[4],   sizeof(str) = 4*sizeof(char) = 4.

3). sizeof(express),其中的express在編譯過程中是不會被編譯的,而是被替代型別。

     例如: int a = 1; sizeof(a=2);

     此時的express為a=2,在編譯過程中被替換為sizeof(int),所以在執行完之後,a仍然是等於1.

4). 對函式使用sizeof,在編譯階段會被替換為函式的返回值的型別取代

     例如: int f(){return 0;}  sizeof(f());的結果為4.

             void f(){}            sizeof(f());編譯過程中會出現錯誤,替換之後的sizoeof(void)編譯無法通過.