?? 05章 指針與字符串.txt
字號(hào):
34 for (int pass = 0; pass < size - 1; pass++ )
35
36 for (int j = 0; j < size - 1; j++ )
37
38 if ( array[ j ] > array[ j + 1 ] )
39 swap( &array[ j ], &arra[ j + 1 ] );
4O }
41
42 void swap( int *element1Ptr, int *element2Ptr )
43 {
44 int hold = *elementlPtr;
45 *element1Ptr = *element2Ptr;
46 *element2Ptr = hold;
47 }
輸出結(jié)果:
Data item: in Original Order
2 6 4 8 10 12 89 68 45 37
Data items in ascendinq Order
2 4 6 8 lO 12 37 45 68 89
圖5.15 按引用調(diào)用的冒泡排序
注意函數(shù)bubbleSort中的幾個(gè)特性。函數(shù)首部中將array聲明為int* array而不是int array[],表示bubbleSort接收單下標(biāo)數(shù)組作為參數(shù)(這些符號(hào)是可以互換的)。參數(shù)size聲明為const以保證最低權(quán)限原則。盡管參數(shù)size接收main中數(shù)值的副本,且修改該副本并不改變main中的值,但是bubbleSort不必改變size即可完成任務(wù)。bubbleSort執(zhí)行期間數(shù)組的長(zhǎng)度保持不變,因此,size聲明為const以保證不被修改。如果排序過程中修改數(shù)組長(zhǎng)度,則排序算法無法正確執(zhí)行。
bubbleSort函數(shù)體中包括了函數(shù)swap的原型,因?yàn)樗钦{(diào)用swap的惟一函數(shù)。將原型放在bubbleSort中,使得只能從bubbleSort正確地調(diào)用swap。其他函數(shù)要調(diào)用swap時(shí)無法訪問正確的函數(shù)原型,這通常會(huì)造成語(yǔ)法錯(cuò)誤,因?yàn)镃++需要函數(shù)原型。
軟件工程視點(diǎn)5.4
將函數(shù)原型放在其他函數(shù)中能保證最低權(quán)限原則,只能從該原型所在函數(shù)中正確地調(diào)用。
注意函數(shù)bubbleSort接收數(shù)組長(zhǎng)度參數(shù)。函數(shù)必須知道數(shù)組長(zhǎng)度才能排序數(shù)組。數(shù)組傳遞到函數(shù)時(shí),函數(shù)接收數(shù)組第一個(gè)元素的內(nèi)存地址。數(shù)組長(zhǎng)度要單獨(dú)傳遞給函數(shù)。
通過將函數(shù)bubbleSort定義成接收數(shù)組長(zhǎng)度作為參數(shù),可以讓函數(shù)在排序任何長(zhǎng)度單下標(biāo)整型數(shù)組的程序中使用。
軟件工程視點(diǎn)5.5
向函數(shù)傳遞數(shù)組時(shí),同時(shí)傳遞數(shù)組長(zhǎng)度(而不是在函數(shù)中建立數(shù)組長(zhǎng)度信息),這樣能使函數(shù)更加一般化,以便在許多程序中復(fù)用。
數(shù)組長(zhǎng)度可以直接編程到函數(shù)內(nèi),這樣會(huì)把函數(shù)的使用限制在特定長(zhǎng)度的數(shù)組并減少其復(fù)用性。程序中只有處理特定長(zhǎng)度的單下標(biāo)整型數(shù)組時(shí)才能使用這個(gè)函數(shù)。
C++提供一元運(yùn)算符sizeof,確定程序執(zhí)行期間的數(shù)組長(zhǎng)度或其他數(shù)據(jù)類型長(zhǎng)度(字節(jié)數(shù))。采用數(shù)組名時(shí)(如圖5.16所示),sizeof算符返回?cái)?shù)組中的總字節(jié)數(shù)為size_t類型的值,通常是unsigned int類型。這里使用的計(jì)算機(jī)將float類型的變量存放在4字節(jié)內(nèi)存中,array聲明為20個(gè)元素,因此array使用80字節(jié)內(nèi)存空間。在接收數(shù)組參數(shù)的函數(shù)中采用指針參數(shù)時(shí),sizeof運(yùn)算符返回指針長(zhǎng)度的字節(jié)數(shù)(4)而不是數(shù)組長(zhǎng)度。
常見編程錯(cuò)誤5. 7
在函數(shù)中用sizeof運(yùn)算符尋找數(shù)組參數(shù)長(zhǎng)度的字節(jié)數(shù)時(shí)返回指針長(zhǎng)度的字節(jié)數(shù)而不是數(shù)組長(zhǎng)度的字節(jié)數(shù)。
1 // Fig. 5.16: fig05_16.cpp
2 // Sizeof operator when used on an array name
3 // returns the number of bytes in the array.
4 #include <iostream.h>
5
6 size_t getSize( float * );
7
8 int main()
9 {
10 float array[ 20 ];
11
12 cout << "The number of bytes in the array is"
13 << sizeof( array )
14 << "\nThe number of bytes returned by getSize is"
15 << getSize( array ) << endl;
16
17 return 0;
18 }
19
20 size_t getSize( float *ptr )
21 {
22 return sizeof( ptr );
23 }
輸出結(jié)果:
The number of bytes in the array is 80
The number of bytes returned by getSize is 4
圖5.16 采用數(shù)組名時(shí),sizeof運(yùn)算符返回?cái)?shù)組中的總字節(jié)數(shù)
數(shù)組中的元素個(gè)數(shù)也可以用兩個(gè)sizeof操作的結(jié)果來確定。例如,考慮下列數(shù)組聲明:
double realArray[ 22 ];
如果double數(shù)據(jù)類型的變量存放在8個(gè)字節(jié)的內(nèi)存中,則數(shù)組realArray總共包含176個(gè)字節(jié)。要確定數(shù)組中的元素個(gè)數(shù),可以用下列表達(dá)式:
sizeof realArray/sizeof(double)
這個(gè)表達(dá)式確定realArray數(shù)組中的字節(jié)數(shù).并將這個(gè)值除以內(nèi)存中存放—個(gè)double值的字節(jié)數(shù),圖5.17的程序用size運(yùn)算符計(jì)算我們所用的個(gè)人計(jì)算機(jī)上存放每種標(biāo)準(zhǔn)數(shù)據(jù)類型時(shí)使用的字節(jié)數(shù)。
可移植性提示 5.3
存放特定數(shù)據(jù)類型時(shí)使用的字節(jié)數(shù)隨系統(tǒng)的不同而不同。編寫的程序依賴于數(shù)據(jù)類型長(zhǎng)度而且要在幾個(gè)計(jì)算機(jī)系統(tǒng)上運(yùn)行時(shí),用sizeof確定存放這種數(shù)椐類型時(shí)使用的宇節(jié)數(shù)。
1 // Fig. 5.17:fig05 17.cpp
2 // Demonstrating the sizeof operator
3 ~include <iostream.h>
4 ~include <iomanip.h>
5
76 ~nt main(}
8 char c;
9 short s;
10 iht i;
11 long 1;
12 float f;
13 double d;
14 long double ld;
15 int arras 20 ], *ptr = array;
16
17 cout << "sizeof c = " << sizeof c
18 << "\tsizeof(char) =" << sizeof( char )
19 << "\nsizeof s = "<< sizeof s
20 << "\tsizeof(short) = "<< sizeof( short )
2I "\nsizeof i = " << sizeof i
22 << "\tsizeof(int) =" << sizeof (int )
23 "\nsizeof 1 = "<<sizeof 1
24 << "\tsizeof(long) =" << sizeof( long )
25 << "\nsizeof f = "<< sizeof f
27 "\nsizeof d =" << sizof d
28 << "\tsizeof(double) =" << sizeof( double )
29 << "\nsizeof ld =" << sizeof ld
30 << "\tsizeof(long double) = "<< sizeof( long double )
31 << "\nsizeof array = "<< sizeof array
32 << "\nsizeof ptr = "<< sizeof ptr
33 << endl;
34 return 0;
35 }
輸出結(jié)果:
sizeof c = 1 sizeof(char) = 1
sizeof s = 2 sizeof(short) = 2
sizeof i = 4 sizeof(int) = 4
sizeof l = 4 sizeof(long) = 4
sizeof f = 4 sizeof(float) = 4
sizeof d = 8 sizeof(double) = 8
sizeof ld = 8 sizeof(long double) = 8
sizeof array =
sizeof ptr = 4
圖 5.17 用sizeof運(yùn)算符計(jì)算存放每種標(biāo)準(zhǔn)數(shù)據(jù)類型時(shí)使用的字節(jié)數(shù)
sizeof運(yùn)算符可以用于任何變量名、類型名或常量值。用于變量名(不是數(shù)組名)和常量值時(shí),返回存放特定變量或常量類型所用的字節(jié)數(shù)。注意,如果提供類型名操作數(shù),則sizeof使用的括號(hào)是必需的;如果提供變量名操作數(shù),則sizeof使用的括號(hào)不是必需的。記住,sizeof是個(gè)運(yùn)算符而不是個(gè)函數(shù)。
常見編程錯(cuò)誤5.8
如果提供類型名操作數(shù),而不在sizeof操作中使用括號(hào)則是個(gè)語(yǔ)法錯(cuò)誤。
性能提示5.2
sizeof屬于編譯時(shí)的一元運(yùn)算符,而不是個(gè)執(zhí)行時(shí)函數(shù)。這樣,使用sizeof并不對(duì)執(zhí)行性能遣成不良影響。
5.7 指針表達(dá)式與指針?biāo)惴? 指針是算術(shù)表達(dá)式、賦值表達(dá)式和比較表達(dá)式中的有效操作數(shù)。但是,通常并不是這些表達(dá)式中使用的所有運(yùn)算符都在指針變量中有效。本節(jié)介紹可以用指針操作數(shù)的運(yùn)算符及這些運(yùn)算符的用法。
只有少量操作可以對(duì)指針進(jìn)行。指針可以自增(++)或自減(--),整數(shù)可以加進(jìn)指針中(+或+=),也可以從指針中減去整數(shù)(-或-=),指針可以減去另一指針。
假設(shè)聲明了數(shù)組int v[5],其第一個(gè)元素位于內(nèi)存地址3000。假設(shè)指針vPtr已經(jīng)初始化為指向數(shù)組v[0],即vPtr的值為3000。圖5.18演示了在32位的機(jī)器中的這種情況。注意vPtr可以初始化為數(shù)組v的指針,如下所示:
vPtr = v;
vPtr = &v[ 0 ]
圖5.18 數(shù)組v和指向v的指針變量vPtr
可移植性提示5.4
如今的大多數(shù)計(jì)算機(jī)都是16位或32位,有些較新的計(jì)算機(jī)用8字節(jié)整數(shù)。由于指針?biāo)惴ǖ慕Y(jié)果取決于指針?biāo)笇?duì)象的長(zhǎng)度,因此指針?biāo)惴ㄅc機(jī)器有關(guān)。
按照傳統(tǒng)算法,3000+2得到3002。而指針?biāo)惴ㄍǔ2皇沁@樣。將指針增加或減去一個(gè)整數(shù)時(shí),指針并不是直接增加或減去這個(gè)整數(shù),而是加上指針?biāo)笇?duì)象長(zhǎng)度的這個(gè)倍數(shù)。這些字節(jié)數(shù)取決于對(duì)象的數(shù)據(jù)類型。例如,下列語(yǔ)句:
vPtr += 2;
在用4字節(jié)內(nèi)存空間存儲(chǔ)整數(shù)時(shí)得到的值為3008(3000+2*4)。對(duì)數(shù)組v,這時(shí)vPtr指向v[2]如圖5.19。如果用2字節(jié)內(nèi)存空間,則上述結(jié)果得到3004(3000+2*2)。如果數(shù)組為不同數(shù)據(jù)類型,則上述語(yǔ)句將指針遞增指針?biāo)笇?duì)象長(zhǎng)度的2倍。對(duì)字符數(shù)組進(jìn)行指針?biāo)惴〞r(shí),結(jié)果與普通算法相同,因?yàn)槊總€(gè)字符的長(zhǎng)度為一個(gè)字節(jié)。
圖 5.19經(jīng)過指針運(yùn)算之后的vPtr
如果vPtr遞增到3016,指向v[4],則下列語(yǔ)句:
vptr -= 4;
將vPtr復(fù)位為3000,即數(shù)組開頭。如果指針加1或減1,則可以用自增(++)和自減(--)運(yùn)算符。
下列語(yǔ)句:
++vptr;
vPtr++;
將指針移到數(shù)組中的下一個(gè)位置。下列語(yǔ)句:
--vPtr;
vPtr --;
將指針移到數(shù)組中的前一個(gè)位置。
指針變量還可以相減。例如,如果vPtr包含地址3000,v2Ptr包含地址3008,則下列浯句:
x = v2Ptr - vPtr;
將x指定為vPtr到v2Ptr的元素個(gè)數(shù),這里為2。指針?biāo)惴ㄖ辉趯?duì)數(shù)組進(jìn)行時(shí)才有意義。我們不能假設(shè)兩個(gè)相同類型的變量在內(nèi)存中相鄰的地址存放,除非它們是數(shù)組的相鄰元素。
常見編程錯(cuò)誤 5.9
對(duì)于不引用數(shù)組值的指針采用指針?biāo)惴ㄍǔJ莻€(gè)邏輯錯(cuò)誤。
常見編程錯(cuò)誤5.10
將兩個(gè)不引用同一數(shù)組的指針相加或相減通常是個(gè)邏輯錯(cuò)誤。
常見編程錯(cuò)誤5.11
使用指針?biāo)惴〞r(shí)超過數(shù)組邊界通常是個(gè)邏輯錯(cuò)誤。
如果兩個(gè)指針的類型相同,則可以將一個(gè)指針賦給另一個(gè)指針。否則要用強(qiáng)制類型轉(zhuǎn)換運(yùn)算符將賦值語(yǔ)句右邊的指針值轉(zhuǎn)換為賦值語(yǔ)句左邊的指針值。這個(gè)規(guī)則的例外是void的指針(即void),該指針是個(gè)一般性指針,可以表示任何指針類型。所有指針類型都可以賦給void指針而不需要類型轉(zhuǎn)換。但是,void指針不能直接賦給另一類型的指針,而要先將void指針轉(zhuǎn)換為正確的指針類型。
void*指針不能復(fù)引用。例如,編譯器知道int指針指向32位機(jī)器中的4字節(jié)內(nèi)存,但void指針只是包含未知數(shù)據(jù)類型的內(nèi)存地址,指針?biāo)傅淖止?jié)數(shù)是編譯器所不知道的。編澤器要知道數(shù)據(jù)類型才能確定該指針復(fù)引用時(shí)的字節(jié)數(shù)。對(duì)于void指針,無法從類型確定字節(jié)數(shù)。
常見編程錯(cuò)誤5.12
除了void*類型外,將一種類型的指針賦給另一種類型的指針而不先將一種類型的指針轉(zhuǎn)換為另一種類型的指針是個(gè)語(yǔ)法錯(cuò)誤。
常見編程錯(cuò)誤5.13
復(fù)引用void*指針是個(gè)語(yǔ)法錯(cuò)誤。
指針可以用相等和關(guān)系運(yùn)算符比較,但這種比較只在對(duì)相同數(shù)組成員進(jìn)行時(shí)才有意義。指針比較是對(duì)指針存放的地址進(jìn)行比較。例如,比較指向同一數(shù)組的兩個(gè)指針可以表示一個(gè)指針?biāo)傅脑靥?hào)比另一個(gè)指針?biāo)傅脑靥?hào)更高。指針比較常用于確定指針是否為0。
5.8 指針與數(shù)組的關(guān)系
C++中指針與數(shù)組關(guān)系密切,幾乎可以互換使用。數(shù)組名可以看成常量指針,指針可以進(jìn)行任何有關(guān)數(shù)組下標(biāo)的操作。
編程技巧5. 4
操作數(shù)組時(shí)用數(shù)組符號(hào)而用指針符號(hào)。盡管程序編譯時(shí)間可能稍長(zhǎng)一些.但程序更加清晰。
假設(shè)聲明了整數(shù)數(shù)組b[ 5 ]和整數(shù)指針變量bPtr。由于數(shù)組名(不帶下標(biāo))是數(shù)組第一個(gè)元素的指針.因此可以用下列語(yǔ)句將bPtr設(shè)置為b數(shù)組第一個(gè)元素的地址:
bPtr = b;
這等于取數(shù)組第一個(gè)元素的地址,如下所示:
bPtr=&b[ O ];
數(shù)組元素b[3]也可以用指針表達(dá)式引用:
*( bPtr + 3 )
上述表達(dá)式中的3是指針的偏移量(offset)。指針指向數(shù)組開頭時(shí),偏移量表示要引用的數(shù)組元素,偏移量值等于數(shù)組下標(biāo)。上述符號(hào)稱為指針/偏移量符號(hào)(pointer/offset notation)。括號(hào)是必需的,因?yàn)?的優(yōu)先順序高于+的優(yōu)先順序。如果沒有括號(hào),則上述表達(dá)式將表達(dá)式*bPtr的值加上3(即3加到b[0]中,假設(shè)bPtr指向數(shù)組開頭)。就像數(shù)組元素可以用指針表達(dá)式引用一樣,下列地址:
&b[ 3 ]
可以寫成指針表達(dá)式:
bPtr + 3
數(shù)組本身可以當(dāng)作指針并在指針?biāo)惴ㄖ惺褂?。例如,下列表達(dá)式:
*( b + 3)
同樣引用數(shù)組元素b[3]。一般來說,所有帶下標(biāo)的數(shù)組表達(dá)式都可以寫成指針加偏移量,這時(shí)使 用指針/偏移量符號(hào),用數(shù)組名作為指針。注意,上述語(yǔ)句不修改數(shù)組名,b還是指向數(shù)組中第一個(gè)元素指針和數(shù)組一樣可以加下標(biāo)。例如,下列表達(dá)式:
bPtr[ 1 ]
指數(shù)組元素b[1].這個(gè)表達(dá)式稱為指針/下標(biāo)符號(hào)(pointer/subscript notation)。
記住,數(shù)組名實(shí)際上是個(gè)常量指針,總是指向數(shù)組開頭。因此下列表達(dá)式:
b += 3
是無效的,因?yàn)樵摫磉_(dá)式試圖用指針?biāo)惴ㄐ薷臄?shù)組名的值。
常見編程錯(cuò)誤5.14
盡管數(shù)組是指向數(shù)組開頭的S針,而指針可以在算術(shù)表達(dá)式中修改,但數(shù)組名不可以在算術(shù)表達(dá)式中修改,囚為數(shù)組名實(shí)際上是個(gè)常量指針。
圖5. 20的程序用我們介紹的四種方法引用數(shù)組元素(數(shù)組下標(biāo)、用數(shù)組名作為指針的指針/偏移量符號(hào)、指針下標(biāo)和指針的指針/偏移量符號(hào),打印數(shù)組的的4個(gè)元素)。
要演示數(shù)組和指針的互換性,還可以看看程序5.21中的兩個(gè)字符串復(fù)制函數(shù)copy1和copy2。
這兩個(gè)函數(shù)都是將字符串復(fù)制到字符數(shù)組中。比較copy1和copy2的函數(shù)原型可以發(fā)現(xiàn),函數(shù)基本相同(由于數(shù)組和指針具有互換性)。這些函數(shù)完成相同的任務(wù),但用不同方法實(shí)現(xiàn)。
1 // Fig. 5.20: f~g05_20.cpp
2 // Using subscripting and pointer notations with arrays
3
4 #include <iostream.h>
5
6 int main()
7{
8 int b[] = { 10, 20, 30, 40 } ;
9 int *bPtr = b; // set bPtr to point to array b
10
11 cout << "Array b printed with:\n"
12 << "Array subscript notation\n";
13
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -