?? 05章 指針與字符串.txt
字號:
14 for(int i = 0; i < 4; i++ ),
15 cou << "b[ " << i << "] = << b[ i ] << '\n';
16
17
18 cout << "\nPointer/offset notation where\n"
19 << "the pointer is the array name\n";
2O
21 for (int offset = 0; offset < 4; offset++ )
22 cout << "* (b +" << offset << ") ="
23 << *( b + offset ) << '\n';
24
25
26 cout << "\nPointer subscript notation\n";
28 for ( i = 0; i < 4; i++ )
29 cout << "bPtr[" << i << "] =" << bPtr[ i ] << '\n';
31 cout << "\nPointer/offset notation\n";
32
33 for ( offset = 0; offset < 4; offset++ )
34 cout << "*(bPtr + "<< offset << ") ="
35 << * ( bPtr + offset ) << '\ n';
36
37 return 0;
38 }
輸出結果:
Array b Printed with:
Array subscript notation
Pointer/offset notation where
the pointer is the array name
* (b + 0) = 10
* (b + 1) = 20
* (b + 2) = 30
* (b + 3) = 40
Pointer subscript notation
bPtr[ 0 ] = 10
bPtr[ 1 ] = 20
bPtr[ 2 ] = 30
bPtr{ 3 ] = 40
Pointer/offset notation
*(bPtr + 0) = 10
*(bPtr + 1) = 20
*(bPtr + 2) = 30
*(bPtr + 2) = 40
圖5.20 用我們介紹的四種方法引用數組元素
1 // Fig. 5.21: figOS_21.cpp
2 // Copying a string using array notation
3 // and pointer notation.
4 #include <iostream.h>
5
6 void copy1( char *, const char * );
7 void copy2( char *, const char * );
8
9 int main()
10 {
11
12 string3[ 10 ], string4[] = "Good Bye";
13
14 copy1( string1, string2 );
15 cout << "string1 =" << string1 << endl;
16
17 copy2( string3, string4 );
18 cout << "string3 = "<< string3 << endl';
19
20 return 0;
21 }
22
23 // copy s2 to sl using array notation
24 void copy1( char *s1, const char *s2 )
25 {
26 for ( int i = 0; ( s1[ i ] = s2[ i ] ) != '\0'; i++ )
27 ; // do nothing in body
28 }
29
30 // copy s2 to sl using pointer notation
31 void copy2( char *s1, const char *s2 )
32 {
33 for ( ; ( *s1 = *s2 ) != '\0'; s1++, s2++ )
34 ; // do nothing in body
35 }
輸出結果:
string1 = Hello
string3 = Good Bye
圖5.21 使用數組和指針符號復制字符串
函數copy1用數組下標符號將s2中的字符串復制到字符數組s1中。函數聲明一個作為數組下標的整型計數器變量i。for結構的首部進行整個復制操作,而for結構體本身是個空結構。首部中指定i初始化為0,并在每次循環時加1。for的條件“(s1[i]=s2[i])!='\0',從s2向s1一次一個字符地進行復制操作。遇到s2中的null終止符時,將其賦給s1,循環終止,因為null終止符等于'\0'。
記住.賦值語句的值是賦給左邊參數的值。
函數copy2用指針和指針算法將s2中的字符串復制到s1字符數組。同樣是在for結構的首部進行整個復制操作.首部沒有任何變量初始化。和copy1中一樣,條件(*s1=*s1)!='\0'進行復制操作。
復引用指針s2,產生的字符賦給復引用的指針s1。進行條件中的賦值之后,指針分別移到指向s1數組的下一個元素和字符串s2的下一個字符。遇到s2中的null終止符時,將其賦給s1,循環終止。
注意copy1和copy2的第一個參數應當是足夠大的數組,應能放下第二個參數中的字符串,否則可能會在寫人數組邊界以外的內存地址時發生錯誤。另外,注意每個函數中的第二個參數聲明為const char*(常量字符串)。在兩個函數中,第二個參數都復制到第一個參數,一次一個地從第二個參數復制字符,但不對字符做任何修改。因此,第二個參數聲明為常量值的指針,實施最低權限原則。兩個函數都不需要修改第二個參數,因此不向這兩個函數提供修改第二個參數的功能。
5.9 指針數組
數組可以包含指針,這種數據結構的常見用法是構成字符串數組,通常稱為字符串數組(stringarray)。字符串數組中的每項都是字符串,但在C++中,字符串實際上是第一個字符的指針。因此,字符串數組中的每項實際上是字符串中第一個字符的指針。下列字符串數組suit的聲明可以表示一副牌:
char‘*suit[ 4 ] = { "Hearts","Diamonds","Clubs","Spades"};
聲明的suit[4]部分表示4個元素的數組。聲明的char*部分表示數組suit的每個元素是char類型的指針。數組中的4個值為”Hearts'’、”Diamonds”、”Clubs”和”Spades”。每個值在內存中存放成比引號中的字符數多一個字符的null終上字符串。4個字符串長度分別為7、9、6、7。盡管這些字符串好像是放在suil數組中,其實數組中只存放指針(如圖5.22)。每個指針指向對應字符串中的第一個字符。這樣,盡管:suit數組是定長的,但可以訪問任意長度的字符串,這是C++強大的數據結構功能所帶來的靈活性。
圖5. 22 suit數組的圖形表示
suit字符串可以放在雙下標數組中,每一行表示一個suit,每一列表示suit名的第一個字符、這種數據結構每一行應有固定列數,能夠放下最長的字符串。因此,存放大量字符串而大部分字符串長度均比最長字符串短許多時,可能浪費很多內存空間。我們將在下一節用字符串數組幫助整理一副牌。
5.10 實例研究:洗牌與發牌
本節用隨機數產生器開發一個洗牌與發牌程序。這個程序可以用于實現玩某種牌的游戲程序。
為了解決一些微妙的性能問題,我們故意用次優洗牌與發牌算法。練習中要開發更有效的算法。
利用自上而下逐步完善的方法,我們開發一個程序,洗52張牌并發52張牌。自上而下逐步完善的方法在解決大而復雜的問題時特別有用。
我們用4 x 13的雙下標數組deck表示要玩的牌(如圖5.23)。行表示花色,0表示紅心,1表示方塊,2表示梅花,3表示黑桃。列表示牌的面值,0到9對應A到10,10到12對應J、Q、K。我們要裝入字符串數組suit,用字符串表示4個花色,用字符串數組face的字符串表示13張牌的面值。
這堆牌可以進行如下的洗牌:首先將數組deck清空,然后隨機選擇row(0--3)和column(0—12)。將數字插入數組元素deck[row][column](表示這個牌是洗出的牌中要發的第一張牌)。繼續這個過程,在deck數組中隨機插入數字2、3、…52,表示洗出的牌中要發的第二、三、…、五十二張牌。在deck數組填上牌號時,一張牌可能選擇兩次,即選擇的時候deck[row][column]為非0值。
忽略這個選擇,隨機重復選擇其他row和colunm,直到找出未選擇的牌。最后,在52個deck元素中插入1到52的值。這時,就完全洗好了牌。
圖5.23 雙下標數組deck表示要玩的牌
這個洗牌算法在隨機重復選擇已經洗過的牌時可能需要無限長的時間。這種現象稱為無窮延遲(indefinite postponement)。練習中將介紹更好的洗牌算法,消陳無窮延遲。
性能提示5.3
有時自然方式的算法可能包含無窮延遲等微妙的性能問題,應尋找能避免無窮延遲的算法。
要發第一張牌,我們要尋找匹配1的deck[row][column]元素,這是用嵌套for結構進行的,n,w取。到3t column取。到12。這個數組元素對應哪種牌呢?suit數組預先裝入了四種花色,因此要取花色,只要打印字符串suit[row];同樣,要取牌值,只要打印字符串face[column]還要打印字符串”of",按正確的順序打印,即可得到每張牌如”King of Clubs"、”Ace of Diamonds',等等。
下面用自上而下逐步完善的方法進行。頂層為:
Shuffle and deal 52 cards
第一步完善結果為:
Initialize the suit array
Initialize the face array
Initialize the deck array
Shuffle the deck
Deal 52 cards
”Shumelhedeck”可以展開成:
For each of the 52 cards
Place card number in randomly selected unoccupied slot of deck
"Deal 52 cards" 可以展開成:
For each of the 52 cards
Find card number in deck array and print face and suit of card
合在一起得到第二步完善結果為:
Initialize the suit array
Initialize the face array
Initialize the deck array
For each of the 52 cards
Place card number in randomly selected unoccupied slot of deck
For each of the 52 cards
Find card number in deck array and print face and suit of card
"Place eard numberin radomly selected unoccupied slot of deck" 可以展開成:
Choose slot of deck randomly
While chosen slot of deck has been previously chosen
Choose slot of deck randomly
Place card number in chosen slot of deck
"Find card numberin deck array and printface and suit of card" 可以展開成:
For each slot of the deck array
If slot contains card number
Print the face and suit of the card
合在一起得到第三步完善結果為:
Initialize the suit array
Initialize the face array
Initialize the deck array
For each of the 52 cards
Choose slot of deck randomly
While slot of deck has been previously chosen
Choose slot of deck randomly
Place card number in chosen slot of deck
For each of the 52 cards
For each slot of deck array
If slot contains desired card number
Print the face and suit of the card
這樣就完成了完善過程。注意,如果將洗牌與發牌算法組合成每張牌在放到牌堆上時進行發牌,則這個程序能更加有效。我們選擇分別編程這些操作,因為通常是先洗后發,而不是邊洗邊發。
圖5.24顯示了洗牌與發牌程序,圖5.25顯示了示例執行結果。注意函數deal中使用的輸出格式:
cout << setw( 5 ) << setiosflags( ios::right )
<< wFace[ column ] << "of"
<< setw( 8 ) << setiosflags( ios::left )
<< wSuit[ row ]
<< (card % 2 ==0? '\n': '\t');
上述輸出語句使牌的面值在5個字符的域中右對齊輸出,而花色在8個字符的域中左對齊輸出。輸出打印成兩列格式。如果輸出的牌在第一列,則在后面輸出一個制表符,移到第二列,否則輸出換行符。
1 // Fig. 5.24: fig05_24.cpp
2 // Card shuffling and dealing program
3 #include <iostream.h>
4 #include <iomanip.h>
5 #include <stdlib.h>
6 #include <time.h>
7
8 void shuffle( iht [][ 13 ] );
9 void deal( const int [][ 13 ], const char *[], const char *[] );
10
11 int main()
12 {
13 const char * suit[ 4 ] =
14 { "Hearts", "Diamonds", "Clubs", "Spades" };
15 const char * face[ 13 ] =
16 { "Ace", "Deuce", "Three", "Four",
17 "Five", "Six", "Seven", "Eight",
18 "Nine", "Ten", "Jack", "Queen", "King" };
19 int deck[ 4 ][ 13 ] = { 0 } ;
20
21 srand( time( 0 ) );
22
23 shuffle( deck );
24 deal( deck, face, suit ):
25
26 return 0;
27 }
28
29 void shuffle( int wDeck[ ][ 13 ] )
30 {
31 int row, column;
32
33 for(int card = 1; card <= 52; card++ ) {
34 do{
35 row = rand() % 4;
36 column = rand() % 13;
37 } while( wDeck[ row ][ column ] != 0 );
38
39 wDeck[ row ][ columo ] = card;
40 }
41 }
42
43 void deal( const int wDeck[ ][ 13 ], const char * wFace[ ] ,
44 const char *wSuit[] )
45 {
46 for (int card = 1; card <= 52; card++ )
47
48 for ( int row = 0; row <= 3; row++ )
49
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -