340 likes | 396 Views
Chapter 08. Pointers and Pointer-Based Strings (Part II). 8.8 指標運算式與指標算式. 指標可做遞增 / 遞減運算 指標可加上一個整數以得到一個新的位址。 除非是使用指標來指向一個陣列,否則指標運算式不具意義的。. 8.8 指標運算式與指標算式. 假設我們宣告一個擁有五個元素的整數陣列 v ,且令一個整數( integer )為 4 個 bytes 令 vPtr 是一個指標,且 vPtr 指向第一個元素 v[0] ,假設其記憶體位址在 3000 vPtr = &v[ 0 ];
E N D
Chapter 08 Pointers and Pointer-Based Strings (Part II)
8.8 指標運算式與指標算式 • 指標可做遞增/遞減運算 • 指標可加上一個整數以得到一個新的位址。 • 除非是使用指標來指向一個陣列,否則指標運算式不具意義的。
8.8 指標運算式與指標算式 • 假設我們宣告一個擁有五個元素的整數陣列v,且令一個整數(integer)為4個bytes • 令vPtr是一個指標,且vPtr指向第一個元素v[0],假設其記憶體位址在3000 vPtr = &v[ 0 ]; • 「vPtr += 2;」的結果將使得vPtr指向3008 • 因為3000 + 2 * 4=3008,換句話說,vPtr將指向v[ 2 ]的位址。 • 註: • 一個整數到底以幾個bytes表示?這是machine dependent的。意指這是可能隨著平台/作業系統不同而不同。
vPtr = &v[ 0 ]; • vPtr += 2;
常見的程式設計錯誤8.9 • 如果對一個指向非陣列的指標來做指標運算的話,將有可能會造成邏輯錯誤。 • 錯誤示範: • 如果對一個指向陣列的指標來做指標運算時,注意不要超過陣列範圍。 int x; int *xPtr = &x; xPtr++; cout << *xPtr << endl;
8.8 指標運算式與指標算式 • 指標的指定 • 指標變數的內容(記憶體位址)可以被指定給另一個同型態的指標變數 • 範例: int x; int *xPtr = &x; int *yPtr = xPtr; double *d = xPtr; //錯誤
8.10 指標陣列 • 一個指標變數 • char *s = “hello”; • s代表指向字元陣列的指標變數。 • 所以一般我們看到char *、int *時,除了想到這是一個位址的指標變數之外,也會把他看成是一個(未定義長度的)陣列。 • 「char *」一般看成是一個字串的型態。 h e l l o s
8.10 指標陣列 • 很多指標變數 • 存在陣列當中,每一個元素都是指標變數(每一個元素都儲存記憶體位址) • 範例 const char *suit[ 4 ] = { "Hearts", "Diamonds", "Clubs", "Spades" }; • Each element of suit points to a char * (string) • 回答以下問題: suit是一個陣列 • 有_______個元素(固定大小)。 • 每一個元素的型態是______________,代表每一個元素儲存的是一個_____________________。 • 每一個元素所指向的字串長度不一。
指標陣列圖示 char * suit [ 4 ];
指標陣列與二維陣列的差別 char s[3][4]; char *s[3]; 0 1 2 3 s[0] s[0] s[1] s[1] s[2] s[2] s s[0] s[1] s[2]
8.13 指標字串處理簡介 • 本節將介紹輔助字串處理的標準函式庫函式。 • 字串處理主要是以字元為基礎。 • 字元常數 • 整數值,代表字元的ASCII編碼。 • 以字元兩邊加上單引號來表示,例如: • ' z ' 代表z的整數值 • ASCII碼為122 • ' \n ' 代表換行字元(newline)的整數值 • ASCII碼為10
8.13.1 字串與指標字串基礎 • 字串 • 一連串字元的組合。 • 字串常數,以雙引號將字串的內容括起來。如: "I like C++“ • 字串可視為一個以結束字元(’\0’)結尾的字元陣列。或一個指向字元陣列的指標。
8.13.1 字串與指標字串基礎 • 宣告字串與初始化 • 字元陣列 • char color[] = "blue"; • 以上的敘述產生一個有五個元素的字元陣列 • 自動補‘\0’到最後一個元素 • 指向字元的指標變數(char *) • char *colorPtr = "blue"; • 產生一個指標變數colorPtr指向字串(字元陣列)“blue”的第一個元素。 • 注意:“blue”所在的位址在記憶體的其他地方。 • 字串的其他宣告法 • char color[] = { 'b', 'l', 'u', 'e', '\0' }; • 如果字串是一個字元一個字元指定,必須要特別給予結束字元。
常見的程式設計錯誤 • 雖然我們常把char *看成是一個字串,但如果沒有為其配置記憶體就直接存取其中的元素,在執行時便會出現「memory access violations」的錯誤訊息。 char *s; cin >> s; • 因為s是一個指標變數,必須指定給他一個合法的字元陣列,而此字元陣列尚未被宣告(未有配置記憶體來記錄資料)。
常見的程式設計錯誤 • 沒有給予足夠的陣列長度。 • 沒有給予結束字元。
8.13.1字串與指標字串基礎 • 讀取字串 • 指定鍵盤輸入至字串陣列word[ 20 ] • cin >> word; • 此行敘述將讀取字串,直到遇到空白或檔尾(EOF)為止(其他的沒有尚未被讀入的資料將被保留在輸入的暫存區中)。 • 為避免字串的輸入超過陣列的長度,利用setw()設定最多讀取的字元數目: • cin >> setw( 20 ) >> word; • 讀入的字元最多19個,程式自動保留一個空間給結束字元。
8.13.1字串與指標字串基礎 • cin.getline • 讀入一整行的文字;例如 • cin.getline( array, size, delimiter ); • 將一直讀入字元直到以下兩種情況: • 讀入的字元數超過size-1。 • 遇到分界符號(delimiter)。 • 範例: char sentence[ 80 ];cin.getline( sentence, 80, '\n' ); • 讀到79個字元或遇到換行符號('\n')便停止,結果存入sentence中。
8.13.2 字串處理函式庫的字串操作函式 • 必須載入標頭檔<cstring>,可用來 • 處理字串資料。 • 比較字串。 • 搜尋字串內的字元與其他字串。 • 切割字串。 • 資料型別:size_t • 定義於<cstring>,通常為無號整數(unsigned int)或無號長整數(unsigned long)。
include<cstring>標頭檔以載入strcpy and strncpy的宣告 將字串y中的內容拷貝至字串x
將x當中的前14個字元拷貝到y;請注意,這個函式並不會自動補結束字元。將x當中的前14個字元拷貝到y;請注意,這個函式並不會自動補結束字元。 因此呼叫這個函式後一定要記得補結束字元。
include<cstring>標頭檔以載入strcat and strncat的宣告 將s2串接到s1結尾 將s1中的前6個字元加到 s3的結尾,請注意此結果會自動補結束字元。
8.13.2 字串處理函式庫的字串操作函式 • 比較字串 • int strcmp(const char *s1,constchar *s2) • 回傳: • 0:代表兩字串相等 • 負值:代表s1 < s2。 • 正值:代表s1 > s2。 • int strncmp(constchar *s1, constchar *s2, size_t n ) • 比較兩字串前n個字元 • 如果其中一個已經比到結尾,就會提早結束比對。
列印s1與s2比較後的結果 列印s1與s3比較後的結果 列印s3與s1比較後的結果
Portability Tip 8.6 • 請勿直接比較字元的ASCII碼,例如: if ( rating == 65 ) 最好使用 if ( rating == 'A' ) • 因為不同作業平台上所採用的編碼方式不一,第二種寫法較能提升可攜性。
8.13.2 字串處理函式庫的字串操作函式 • 分割字串 • 將字串分隔成tokens • Tokens指的是由分界字元(delimiting characters,例如空白字元)隔開而成的字組/符記。 • 例: char *s1 = “ ”; char *s2 = “ \t\n”; • 範例: • “This is my string”裡有 4 個word tokens (如果以空白隔開的話)。
8.13.2 字串處理函式庫的字串操作函式 • 利用strtok函式分割字串 • char *strtok( char *s1, constchar *s2 ) • 需要重複的呼叫來擷取tokens • 第一次呼叫時需要兩個引數,第一個引數代表需要被擷取的字串,第二個則是包含分界字元的字串。 • 連續地呼叫來將token一一地擷取出來 • 第二次呼叫開始,第一個參數用NULL替代。 • 該函式會將下一次開頭的位址把指標用一個靜態變數(static variable)儲存起來。 • 回傳一個指標指向目前所讀取到的token。
必須include 標頭檔<cstring> 第一次呼叫strtok,回傳的指標指向第一個token的開頭 接下來連續呼叫strtok來讀取下一個token,第一個參數改用NULL代替。當strtok回傳NULL,就代表已經讀到字串結尾了。
常見的程式設計錯誤8.22 • 要瞭解使用strtoken時,會修改到第一個參數所指向的內容,如果在呼叫完strtoken之後再繼續拿第一個參數所代表的字串來做運算,將有可能會發生錯誤。 • 如果日後需要使用該字串,建議在呼叫strtoken之前,先把原字串複製一份,再拿其負本來做strtoken。
strlen()的使用範例 使用strlen來計算字串的長度。