C++ - pointer to char、array of pointer to char、pointer to array of char (C++軟體開發 - 指標與字元與陣列 概念與實例)

基本概念

Data type 

call by value、call by pointer、Call by reference 

簡單實例



pointer to char 

step 1. vas 配置 pointer in memory。
step 2. "Hello" 為 const char array in memory,且不可變(constant)。
step 3. pointer 指向 starting address of this const char array in memory。
step 4. = "新字串",會更動pointer指向新字串。

vas 是 pointer to "不可變"的 const char array "Hello" 的 start address。
雖然可以成功編譯,但是其實是不怎麼好的寫法, 因為將const char array 轉成 非-常數(non-const)的char 指標, 雖然很多compiler為了確保向下兼容(backward compatibility), 而支援這種寫法。

    char *vas = "Hello"; //OK

    //vas[i] 相等於 *(vas + i)
    cout << typeid(vas).name() << endl;//char *
    cout << typeid((*vas)).name() << endl;//char
    cout << typeid(vas[0]).name() << endl;//char
    //pointer 4 bytes 、char 1bytes
    cout << sizeof(vas) << endl;//4
    cout << sizeof((*vas)) << endl;//1
    cout << sizeof(vas[0]) << endl;//1
    //雖然型態是指標,(vas + i ) 值是從指向位址開始的整個 character sequence not its address.
    cout << vas << endl;//Hello
    cout << vas + 1 << endl;//ello
    cout << vas + 2 << endl;//llo
    cout << vas + 3 << endl;//lo
    cout << vas + 4 << endl;//o
    //型態是char,讀取指標指向的its address character value , not 指向位址開始的整個 character sequence.
    cout << *vas << endl;//H
    cout << *(vas + 1) << endl;//e
    cout << *(vas + 2) << endl;//l
    cout << *(vas + 3) << endl;//l
    cout << *(vas + 4) << endl;//o
    //vas[i] 相等於 *(vas + i)
    cout << vas[0] << endl;//H
    cout << vas[1] << endl;//e
    cout << vas[2] << endl;//l
    cout << vas[3] << endl;//l
    cout << vas[4] << endl;//o
    vas = "world";//OK,更動pointer,而非 "不可變"的 const char array "Hello"
    //*vas = 'a';//擲回例外狀況: 寫入存取違規。因為企圖更動 "不可變"的 const char array "Hello"

若替代 const array of char "Hello",為 非const 的char array 
  • 可以對指向的array of char內的字元進行更動。
  • 允許重新指向array of char,且允許重新指向array of char內char數不同。
  • 允許const array of char與array of char之間互相重新指向。
  • 若重新指向const array of char,array of char隱性轉成const,不可以對const array of char中的char進行更動。
  • 若重新指向array of char,可以對array of char中的char進行更動。
    char temp[] = { 'h','e','l','l','o','\0' };
    char temp2[] = { 'w','o','r','l','d','\0' };
    char temp3[] = { 's','w','o','r','l','d','\0' };
    char *vas = temp; //OK

    //vas[i] 相等於 *(vas + i)
    cout << typeid(vas).name() << endl;//char *
    cout << typeid((*vas)).name() << endl;//char
    cout << typeid(vas[0]).name() << endl;//char
    //pointer 4 bytes 、char 1bytes
    cout << sizeof(vas) << endl;//4
    cout << sizeof((*vas)) << endl;//1
    cout << sizeof(vas[0]) << endl;//1
    //雖然型態是指標,(vas + i ) 值是從指向位址開始的整個 character sequence not its address.
    cout << vas << endl;//Hello
    cout << vas + 1 << endl;//ello
    cout << vas + 2 << endl;//llo
    cout << vas + 3 << endl;//lo
    cout << vas + 4 << endl;//o
    //型態是char,讀取指標指向的its address character value , not 指向位址開始的整個 character sequence.
    cout << *vas << endl;//H
    cout << *(vas + 1) << endl;//e
    cout << *(vas + 2) << endl;//l
    cout << *(vas + 3) << endl;//l
    cout << *(vas + 4) << endl;//o
    //vas[i] 相等於 *(vas + i)
    cout << vas[0] << endl;//H
    cout << vas[1] << endl;//e
    cout << vas[2] << endl;//l
    cout << vas[3] << endl;//l
    cout << vas[4] << endl;//o

    *vas = 'a';//OK,非const
    cout << vas << endl;//aello 
    vas = temp2;//OK,更動pointer
    cout << vas << endl;//world
    vas = temp3;//OK,更動pointer,允許array內char數不同
    cout << vas << endl;//sworld
    vas = "another";//OK,更動pointer,but 指向的array隱性轉換成const
    cout << vas << endl;//another
    //*vas = 'x';//擲回例外狀況: 寫入存取違規。因為企圖更動 "不可變"的 const char array "Hello"
    vas = temp3;//OK,更動pointer,but 指向的const array隱性轉換成非const
    *vas = 'x';//OK
    cout << vas << endl;//xworld

以下宣告方式錯誤,因為 *vad[] 為an array of pointer to char ,"Hello"字串明顯不是 an array of pointer to char,理所當然放不進,而放入 pointer to char進array的方法有,
char *vad[] = { "Hello" },為an array of one pointer to the char。
char *vad[] = "Hello"; //ERROR

an array of pointer to char 

    char *vad[] = { "Hello","World" };//OK

    cout << typeid(vad).name() << endl;//char * [2]
    cout << typeid(*vad).name() << endl;//char*
    cout << typeid(vad[0]).name() << endl;//char*
    cout << typeid(*(vad[0])).name() << endl;//char
    //2 pointer 8 bytes 、pointer 4 bytes 、char 1bytes
    cout << sizeof(vad) << endl;//8
    cout << sizeof((*vad)) << endl;//4
    cout << sizeof(vad[0]) << endl;//4
    cout << sizeof(*(vad[0])) << endl;//1
    //型態為an array of pointer to char,cout出的為陣列儲存位址
    cout << vad << endl;//008FF734 
    //相等於vad[i],型態是指標,值是從指向位址開始的整個 character sequence not its address.
    cout << *vad << endl;//Hello
    cout << *(vad + 1) << endl;//World
    //vas[i],型態是指標,值是從指向位址開始的整個 character sequence not its address
    cout << vad[0] << endl;//Hello
    cout << vad[1] << endl;//World
    //型態是char,讀取指標指向的its address character value , not 指向位址開始的整個 character sequence.
    cout << *(vad[0]) << endl;//H
    cout << *(vad[1]) << endl;//W

    vad[0] = "New String";//OK,更動pointer,而非 "不可變"的 char array or string literal "Hello"
    //*(vad[0]) = 'k';//擲回例外狀況: 寫入存取違規。因為企圖更動 "不可變"的 const char array

若替代 array內pointer to char內的指向的const array of char,為 非const 的char array

  • 可以對array內pointer to char指向的array of char內的字元進行更動。
  • 允許array內pointer to char重新指向array of char,且允許重新指向array of char內char數不同 。
  • 允許const array of char與array of char之間互相重新指向 。
  • 若重新指向const array of char,array of char隱性轉成const,不可以對const array of char中的char進行更動。
  • 若重新指向array of char,可以對array of char中的char進行更動。
    char temp[] = { 'h','e','l','l','o','\0' };
    char temp2[] = { 'w','o','r','l','d','\0' };
    char temp3[] = { 's','w','o','r','l','d','\0' };
    char *vad[] = { temp,temp2 };//OK

    cout << typeid(vad).name() << endl;//char * [2]
    cout << typeid(*vad).name() << endl;//char*
    cout << typeid(vad[0]).name() << endl;//char*
    cout << typeid(*(vad[0])).name() << endl;//char
    //2 pointer 8 bytes 、pointer 4 bytes 、char 1bytes
    cout << sizeof(vad) << endl;//8
    cout << sizeof((*vad)) << endl;//4
    cout << sizeof(vad[0]) << endl;//4
    cout << sizeof(*(vad[0])) << endl;//1
    //型態為an array of pointer to char,cout出的為陣列儲存位址
    cout << vad << endl;//008FF734 
    //相等於vad[i],型態是指標,值是從指向位址開始的整個 character sequence not its address.
    cout << *vad << endl;//hello
    cout << *(vad + 1) << endl;//world
    //vas[i],型態是指標,值是從指向位址開始的整個 character sequence not its address
    cout << vad[0] << endl;//hello
    cout << vad[1] << endl;//world
    //型態是char,讀取指標指向的its address character value , not 指向位址開始的整個 character sequence.
    cout << *(vad[0]) << endl;//h
    cout << *(vad[1]) << endl;//w
    *(vad[0]) = 'k';//OK,非const
    cout << vad[0] << endl;//kello 
    vad[0] = "New String";//OK,更動pointer,but 隱性轉換成const
    cout << vad[0] << endl;//New String 
    //*(vad[0]) = 'k';//擲回例外狀況: 寫入存取違規。因為企圖更動 "不可變"的 const char array
    vad[0] = temp3;//OK,更動pointer,but 指向的const array隱性轉換成非const
    *(vad[0]) = 'k';//OK
    cout << vad[0] << endl;//kworld
    
pointer to array of char 

6個陣列元素包含 hello 5個字元 和 '\0'

  • 若採用char (*x)[6] = &"Hello" 的宣告方式,會出錯,因為"Hello"為const arrays of char,必須宣告為char const (*x)[6] 。
  • 不允許對array內的char進行更動,因為array of char宣告為const 。
  • 可對指向的陣列位址進行重新指向 
  • 不允許重新指向的array內char數不同 
  • 不允許對 (*x) assign array,因為arrays are not assignable.
    //pointer to array of char
    //6個陣列元素包含 hello 5個字元 和 '\0'

    //char (*x)[6] = &"Hello"; //error, "Hello" are const arrays of char
    char const (*x)[6] = &"Hello";
    cout << typeid(x).name() << endl;//char const (*)[6]
    cout << typeid(*x).name() << endl;//char const [6]
    cout << typeid(**x).name() << endl;//char
    cout << typeid(x[0]).name() << endl;//char const [6]
    cout << typeid(*x[0]).name() << endl;//char
    //型態為指標,指向 char const [6]
    cout << x << endl;//00366B30 
    //型態為char const [6]
    cout << *x << endl;//Hello 
    //相等於(*x)[i],型態為char
    cout << **x << endl;//H
    //相等於*(x + i),型態為char const [6]
    cout << x[0] << endl;//Hello 
    //相等於**(x + i),型態為char
    cout << *x[0] << endl;//H

    //*x = "world";//error,arrays are not assignable.
    //**x = 's';//error,為const
    //x[0] = "world"//error,arrays are not assignable
    //*x[0] = 'h';//error,為const
    
    char temp[] = { 'w','o','r','l','d','\0' };
    x = &temp;//OK
    cout << x << endl;//00AFFCC0 
    cout << *x << endl;//world
    //x = &"NewString";//error,const char (*)[10] can't assign to const char (*)[6]
    x = &"hello";//OK
    cout << x << endl;//00F06B38 
    cout << *x << endl;//hello
    //x = &"helo";//error,const char (*)[5] can't assign to const char (*)[6]
    char temp2[] = { 'l','w','o','r','l','d','\0' };
    //x = &temp2;//error,const char (*)[7] can't assign to const char (*)[6]

若要宣告非const的char (*x)[6],可以利用非const 的array of char位址。 

  • 不可再重新指向const 的array of char 。
  • 可以對array內的char進行更動。
  • 不允許對 (*x) assign array,因為arrays are not assignable。
    char temp[] = { 'h','e','l','l','o','\0'};
    char temp2[] = { 'w','o','r','l','d','\0' };
    
    char (*x)[6] = &temp; 
    
    cout << typeid(x).name() << endl;//char (*)[6]
    cout << typeid(*x).name() << endl;//char [6]
    cout << typeid(**x).name() << endl;//char
    cout << typeid(x[0]).name() << endl;//char [6]
    cout << typeid(*x[0]).name() << endl;//char
    //型態為指標,指向 char const [6]
    cout << x << endl;//00AFF714 
    //型態為char const [6]
    cout << *x << endl;//hello
    //相等於(*x)[i],型態為char
    cout << **x << endl;//h
    //相等於*(x + i),型態為char const [6]
    cout << x[0] << endl;//hello
    //相等於**(x + i),型態為char
    cout << *x[0] << endl;//h

    //x = &"hello";//error,const char (*)[6] can't assign to char (*)[6],沒有隱性轉換const問題
    x = &temp2;//OK
    cout << x << endl;//00AFF704 
    cout << *x << endl;//world
    //*x = temp2 //error,arrays are not assignable.
    //*x = "world";//error,arrays are not assignable.
    **x = 's';//OK,不為const
    cout << x << endl;//00AFF704,沒變 
    cout << *x << endl;//sorld
    //x[0] = "world"//error,arrays are not assignable.
    *x[0] = 'x';//OK,不為const
    cout << x << endl;//00AFF704,沒變 
    cout << *x << endl;//xorld

留言