字符數組與字符指針
1.字符指針可以指向一個字符串。
我們可以用字符串常量對字符指針進行初始化。例如,有說明語句:
char *str = "This is a string.";
是對字符指針進行初始化。此時,字符指針指向的是一個字符串常量的首地址,即指向字符串的首地址。
這裏要註意字符指針與字符數組之間的區別。例如,有說明語句:
char string[ ]="This is a string.";
此時,string是字符數組,它存放了一個字符串。
字符指針str與字符數組string的區別是:str是一個變量,可以改變str使它指向不同的字符串,但不能改變str所指的字符串常量。string是一個數組,可以改變數組中保存的內容。
2.實例:
char *str, *str1="This is another string."; char string[100]="This is a string.";
則在程序中,可以使用如下語句:
str++; /* 指針str加1 */ str = "This is a NEW string."; /* 使指針指向新的字符串常量 */ str = str1; /* 改變指針str的指向 */ strcpy( string, "This is a NEW string.") /* 改變字符串的的內容 */ strcat( string, str) /* 進行串連接操作 */
在程序中,不能進行如下操作:
string++; /* 不能對數組名進行++運算 */ string = "This is a NEW string."; /* 錯誤的串操作 */ string = str1; /* 對數組名不能進行賦值 */ strcat(str, "This is a NEW string.") /* 不能在str的後面進行串連接 */ strcpy(str, string) /* 不能向str進行串復制 */
3.其它說明:
1) 以字符串形式出現的,編譯器都會為該字符串自動添加一個0作為結束符,如在代碼中寫:"abc",那麽編譯器幫你存儲的是"abc/0"
2) "abc"是常量嗎?答案是有時是,有時不是。
不是常量的情況:"abc"作為字符數組初始值的時候就不是,如
char str[] = "abc";
因為定義的是一個字符數組,所以就相當於定義了一些空間來存放"abc",而又因為字符數組就是把字符一個一個地存放的,所以編譯器把這個語句解析為 char str[3] = {‘a‘,‘b‘,‘c‘};又根據上面的總結1,所以char str[] = "abc";的最終結果是 char str[4] = {‘a‘,‘b‘,‘c‘,‘/0‘};
做一下擴展,如果char str[] = "abc";是在函數內部寫的話,那麽這裏的"abc/0"因為不是常量,所以應該被放在棧上。
是常量的情況: 把"abc"賦給一個字符指針變量時,如
char* ptr = "abc";
因為定義的是一個普通指針,並沒有定義空間來存放"abc",所以編譯器得幫我們找地方來放"abc",顯然,把這裏的"abc"當成常量並把它放到程序的常量區是編譯器最合適的選擇。所以盡管ptr的類型不是const char*,並且ptr[0] = ‘x‘;也能編譯通過,但是執行ptr[0] = ‘x‘;就會發生運行時異常,因為這個語句試圖去修改程序常量區中的東西。
記得哪本書中曾經說過char* ptr = "abc";這種寫法原來在c++標準中是不允許的,但是因為這種寫法在c中實在是太多了,為了兼容c,不允許也得允許。雖然允許,
但是建議的寫法應該是const char* ptr = "abc";這樣如果後面寫ptr[0] = ‘x‘的話編譯器就不會讓它編譯通過,也就避免了上面說的運行時異常。
又擴展一下,如果char* ptr = "abc";寫在函數體內,那麽雖然這裏的"abc/0"被
放在常量區中,但是ptr本身只是一個普通的指針變量,所以ptr是被放在棧上的, 只不過是它所指向的東西被放在常量區罷了。
3) 數組的類型是由該數組所存放的東西的類型以及數組本身的大小決定的。如char s1[3]和char s2[4],s1的類型就是char[3],s2的類型就是char[4],也就是說盡管s1和s2都是字符數組,但兩者的類型卻是不同的。
4) 字符串常量的類型可以理解為相應字符常量數組的類型,如"abcdef"的類型就可以看成是const char[7]
5) sizeof是用來求類型的字節數的。如int a;那麽無論sizeof(int)或者是sizeof(a)都是等於4,因為sizeof(a)其實就是sizeof(type of a)
6) 對於函數參數列表中的以數組類型書寫的形式參數,編譯器把其解釋為普通的指針類型,如對於void func(char sa[100],int ia[20],char *p),則sa的類型為char*,ia的類型為int*,p的類型為char*
7) 根據上面的總結,來實戰一下:
對於char str[] = "abcdef";就有sizeof(str) == 7,因為str的類型是char[7],
也有sizeof("abcdef") == 7,因為"abcdef"的類型是const char[7]。
對於char *ptr = "abcdef";就有sizeof(ptr) == 4,因為ptr的類型是char*。
對於char str2[10] = "abcdef";就有sizeof(str2) == 10,因為str2的類型是char[10]。
對於void func(char sa[100],int ia[20],char *p);
就有sizeof(sa) == sizeof(ia) == sizeof(p) == 4,
因為sa的類型是char*,ia的類型是int*,p的類型是char*。
4.區別:
(1)字符數組由若幹個元素組成,每個元素中存放字符串的一個字符,而字符指針變量中存放的是字符串的首地址。
(2)初始化方式不同。對字符數組初始化要用static存儲類別,在編譯時進行。而對字符指針變量初始化不必加static,在實際執行時進行。
(3)賦值方式不同。對字符數組不能整體賦值,只能轉化成份量,對單個元素進行。而字符指針變量賦值可整體進行。
例如:
char s[10]; s= /"C++/";/*錯,s是常量,怎能被賦值*/
(4)在定義一個字符數組時,編譯時即已分配內存單元,有確定的地址。而定義一個字符指針變量時,給指針變量分配內存單元,但該指針變量具體指向哪個字符串,並不知道,即指針變量存放的地址不確定。例如:
char a[10]; char *p; scanf(/"%s/",s);/*正確*/ scanf(/"%s/",p);/*非常危險,p的值動態*/
(5)字符指針變量的值可以改變,字符數組名是一個常量,不能改變。例如,有簡單程序:
void main() { char *s="china man" s+=6; printf("%s",s); }
運行結果:man
字符數組與字符指針