站在巨人肩上的思考[連載] (8)5.2 數(shù)組5.2.2 字符串文字量類似”this is a string.”這樣一個字符串文字量,它是一個常量。正如代碼中一個顯式的數(shù)字0xff08一樣,其值不可以被更改。如想修改,可以通過復(fù)制給一個變量來實現(xiàn):
int a = 0xff08; a =
0xff18; 對于字符串文字量則有一點要注意:
char* cp = “this is a string”; //危險!賦值給一個普通字符指針; cp[4] = ‘e’; //未定義行為!不能給常量賦值; char p[] = “this is a string”; //可以; p[4] = ‘e’; //正確執(zhí)行; 可以看出,用char *來引用字符串文字量是一個十分危險的地方。在上例中cp[4]=’e’;可以通過編譯,但是在執(zhí)行期間產(chǎn)生了一個Segmentation Fault。也就是說編譯器并不能幫助程序員發(fā)現(xiàn)這類錯誤。 我個人是這樣認(rèn)為的:字符串文字量是一中很底層的數(shù)據(jù),編譯器把他放進匯編語言中的數(shù)據(jù)段;普通的char*指針也是一種很底層的指針,他可以指向內(nèi)存空間中的任何地址;char* cp = “this is a string”;僅僅在??臻g生成一個指針,然后把他指向位于數(shù)據(jù)段的”this is a string”,初始化并不會導(dǎo)致錯誤。但是利用cp[4]更改數(shù)據(jù)段中的數(shù)據(jù)內(nèi)容將會導(dǎo)致段錯誤,數(shù)據(jù)段是只讀的。而利用char p[]形式的時候,意味著將在??臻g中生成一個字符數(shù)組,然后用”this is a string”來進行初始化,而后p指向這個棧空間中字符數(shù)組的首地址。此時p[4]=’e’;修改的是??臻g中的值,而不是數(shù)據(jù)段中的值。 但是p是什么類型呢?是char*么?他的大小是多少?是1么?為了使指針和數(shù)組首地址之間的區(qū)別更具普遍意義,我們用int類型來測試一下:
char p[] = "hello"; char* ptr = p; cout << sizeof(p) << ":"
<< sizeof(*p) << endl; cout << p << ":" << *p
<< endl; cout << sizeof(ptr) << ":"
<< sizeof(*ptr) << endl; cout << ptr << ":" << *ptr
<< endl; 這段代碼在我的電腦上的輸出是:
[/home/gavin/test]# ./test 6:1 hello:h 4:1 hello:h ptr是真正的char*類型,其sizeof是4,但是p的sizeof卻是6,也就是”hello”加一個‘\0’的長度。除此之外,ptr和p表現(xiàn)都一樣。但我們最好認(rèn)為p是字符數(shù)組類型,而ptr才是字符指針類型,因為他們的行為上存在差異。很多教師、教材都說:“數(shù)組名就是指向數(shù)組首地址的指針?!边@其實并不完全正確。 再仔細(xì)看看,我們cout<<p和cout<<ptr的期望輸出應(yīng)該是p和ptr分別表示的地址。但事實上卻是數(shù)組的內(nèi)容。為了明顯區(qū)分,再看下面這段代碼:
int arr[4] = {0}; int* pa = arr; cout << sizeof(arr) << ":"
<< sizeof(*arr) << endl; cout << arr << ":" << *arr
<< endl; cout << sizeof(pa) << ":"
<< sizeof(*pa) << endl; cout << pa << ":" << *pa
<< endl; 在我的電腦上輸出為:
[/home/gavin/test]# ./test 16:4 0xbfc26e5c:0 4:4 0xbfc26e5c:0 sizeof的輸出剛才已經(jīng)說過。這里可以看出,int數(shù)組名和char數(shù)組名的行為也不一樣。事實上,cha數(shù)組名與標(biāo)準(zhǔn)類型數(shù)組名的行為都不一樣。這也就是為什么C風(fēng)格字符串為許多人詬病的地方。 C++在這方面提供了很好的改進:用一種更上層的類型string來代替C風(fēng)格字符串。并強烈建議程序員在程序中盡量使用string來代替char *。這里是你需要做出選擇的地方:
string str1("1"); string str2("1234567"); string
str3("1234567890123456789012345678901234567890"); /* char str1[] = "1"; char str2[] = "1234567"; char str3[] =
"1234567890123456789012345678901234567890"; */ cout << sizeof(str1) <<
endl; cout << sizeof(str2) <<
endl; cout << sizeof(str3) <<
endl; 當(dāng)利用C風(fēng)格字符串的輸出為:
[/home/gavin/test]# ./test 2 8 41 [/home/gavin/test]# ls -l -rwxrwxr-x 1 863 863 6559 Dec
3 14:29 test -rw-rw-r-- 1 863 863 391 Dec
3 14:29 test.cpp 而當(dāng)使用string時:
[/home/gavin/test]# ./test 4 4 4 [/home/gavin/test]# ls -l -rwxrwxr-x 1 863 863 7578 Dec
3 14:30 test -rw-rw-r-- 1 863 863 390 Dec
3 14:30 test.cpp 我們也許可以得到如下結(jié)論:sting比char[]需要更少的運行時內(nèi)存空間,但是char[]卻比string占用更少的磁盤空間。你可以自己選擇向左還是向右走。不過相比string的易用性、安全性、以及諸多的成員函數(shù)帶來的實用功能來說,我個人并不認(rèn)為char[]節(jié)省的磁盤空間是很突出的優(yōu)點。 |
|