C字符串、字符和字節(下)

 

06

高級字符串查找

 

    接下來的一組函數簡化了從一個字符串中查找和抽取一個子串的過程。

1.查找一個字符串前綴

    strspn和strcspn函數用於在字符串的起始位置對字符計數。它們的原型如下:

size_t strspn(char const *str, char const *group);size_t strcspn(char const *str, char const *group);

    group字符串指定一個或多個字符。strspn返回str第一個不在字符串 group中出現的字符下標。例如,如果group包含了空格、製表符等空白字符。

下面例子,

int len1, len2;char buffer[] = "25.142.330,Smith,J,239-4123";len1 = strspn(buffer, "0123456789");len2 = strspn(buffr, ".0123456789");

    變量len1將被置爲2,變量len2將被置爲11。下面的代碼將計算第一個指向字符串中第一個非空白字符的指針。

ptr = buffer + strspn(buffer, "\n\r\f\t");

    strcspn函數和strspn函數正好相反,它將返回第一個在group中的字符的下標。strcspn這個詞中的字母c來源於對一組字符求補這個概念。

 

2.查找標記

    一個字符串常常包含了幾個有意義的部分,它們被分隔符分隔開來。每次爲了處理這些部分,你首先必須把它們從字符串中抽取出來。

    這個任務正是strtok函數所實現的功能。它從字符串中隔離各個單獨的稱爲標記(token)的部分,並丟棄分隔符。它的原型如下:

char *strtok(char *str, char const *sep);

    sep參數是個字符串,定義了用作分隔符的字符集合。第1參數指定一個字符串,它包含零個或多個由sep字符串中一個或多個分隔符分隔的標記。strtok找到str的下一個標記,並將其用NUL結尾,然後返回一個指向這個標記的指針。若沒有可檢索的字符串,則返回一個空指針。

    下面是一個簡短的例子,

char str[80] = "This is - cxsjcrmdjt - official account";const char sep[2] = "-";char *token;/* 獲取第一個子字符串 */token = strtok(str, sep);/* 繼續獲取其他子字符串 */while(token != NULL){    printf("%s\n", token);    token = strtok(NULL, s);}

    編譯並運行上面程序,這將產生以下結果:

This is

cxsjcrmdjt

official account

    如果你願意,你可以在每次調用strtok函數時使用不同的分隔符集合。當一個字符串的不同部分由不同的字符集合分隔的時候,這個技巧很管用。

警告:

    由於strtok函數保存它處理的函數的局部狀態信息,所以你不能用它同時解析兩個字符串,因此,如果while循環體內調用了一個在內部調用strtok函數的函數,上述代碼將會失敗。

 

07

錯誤信息

 

    當你調用一些函數,請求操作系統執行一些功能如打開文件時,如果出現錯誤,操作系統是通過設置一個外部的整型變量errno進行錯誤代碼報告的。strerror函數把其中一個錯誤代碼作爲參數並返回一個指向用於描述錯誤的字符串的指針。這個函數的原型如下:

char *strerror(int error_number);

 

08

字符操作

 

    標準庫包含了兩組函數,用於操作單獨的字符,它們的原型位於頭文件ctype.h。第一組函數用於對字符分類,而第二組用於轉換字符。

1.字符分類

    每個分類函數接受一個包含字符值的整型參數。函數測試這個字符並返回一個整型值,表示真或假。下表列出了這些分類函數以及它們每個所執行的測試。

 

2.字符串轉換

    轉換函數可將大小寫字母相互轉換。

int tolower(int ch);int toupper(int ch);

    如其函數名一樣,toupper函數返回對應的大寫形式,tolower函數返回對應的小寫形式。如果函數的參數並不是一個可以大小寫轉換的字符,函數將不修改參數直接返回。

提示:

    或許你會認爲這些函數的實現簡單,可以很輕易地被自己的實現替代,但是直接操控字符將會降低程序的可移植性,考慮以下例子,它試圖測試ch是否是一個大寫字符。

if (ch >= 'A' && ch <= 'Z')

    這條語句在使用ASCII字符集的機器上能夠運行,但在使用EBCDIC字符集的機器上將會失敗。若使用下面這條語句:

if (isupper(ch))

    無論機器使用哪種字符集,它都能順利執行。

 

09

內存操作

 

    根據定義,字符串由一個NUL字節結尾,所以字符串內部不能包含任何NUL字符。但是,非字符串數據內部包含零值的情況並不罕見,你無法使用字符串函數來處理這種類型的數據,因爲當它們遇到第一個NUL字節時將停止工作。

    不過,我們可以使用另外一組相關的函數,它們的作用於字符串函數類似,但這些函數能夠處理任意的字節序列。下面是它們的原型。

void *memcpy(void *dst, void const *src, size_t length);void *memmove(void *dst, void const *src, size_t length);void *memcmp(void const *a, void const *b, size_t length);void *memchr(void const *a, int ch, size_t length);void *memset(void *a, int ch, size_t length);

    每個原型都包含一個顯式的參數說明需要處理的字節數。但和strn開頭的函數不同,它們在遇到NUL字節時並不會停止操作。

    memcpy從src的起始位置複製length個字節到dst的內存起始位置。你可以用這種方法複製任何類型的值,第三個參數指定複製值的長度(以字節計)。如果src和dst以任何形式出現了重疊,它的結果是未定義的。

例如,

char temp[SIZE], values[SIZE];...memcpy(temp, values, SIZE);

    它從數組values複製SIZE個字節到數組temp。

    但是,如果兩個數組都是整型數組該怎麼辦?下面的語句可以完成這項任務:

memcpy(temp, values, sizeof(values));

    前兩個參數並不需要使用強制類型轉換,因爲在函數的原型中,參數的類型是void*型指針,而任何類型的指針都可以轉換爲void*型指針。

    如果數組只有部分內容需要被複制,那麼需要複製的數量必須在第三個參數中指明。對於長度大於一個字節的數據,要確保把數量和數據類型的長度相乘,如:

memcpy(dst, array, count * sizoef(array[0]));

    你也可以使用這種技巧複製結構體或者結構體數組。

    memmove函數的行爲和memcpy差不多,只是它的源和目的操作數可以重疊。雖然它不需要以下面這種方式實現,不過memmove的過程和這種方法的過程相同:把源操作數複製到一個臨時位置,這個臨時位置不會與源或目標操作數重疊,然後再把它從這個臨時位置複製到目標操作數。memmove通常無法使用某些機器所提供的特殊的字節-字符串處理指令來實現,所以它可能比memcpy慢一些。但是,如果源和目標參數真的可能存在重疊,就應該使用memmove。

    memcmp對兩端內存的內容進行比較,這兩端內存分別起始於a和b,共比較length個字節。這些值按照無符號字符逐字節進行比較,函數的返回類型和strcmp函數一樣----負值表示a小於b,正值表示a大於b,零表示a等於b。由於這些值是根據一串無符號字節進行比較的,所以如果memcmp函數用於比較不是單字節的數據如整數或浮點數時可能會出現不可預料的結果。

    memchr從a的起始位置開始查找字符ch第一次出現的位置,並返回一個指向該位置的指針,它共查找length個字節。如果在這length個字節中未找到該字符,函數就返回一個NULL指針。

    memset函數把從a開始的length個字節都設置爲值ch。如:

memset(buffer, 0, SIZE);

    把buffer的前SIZE個字節都初始化爲0。

 

10

總結

 

    字符串就是零個或多個字符的序列。該序列以一個NUL字節結尾,字符串的長度就是它所包含的字符的數目。標準庫提供了處理字符串的函數,它們的原型位於頭文件string.h中。

    strlen函數用於計算一個字符串的長度,它的返回值是一個無符號整數,所以把它用於表達式時應該小心。strcpy函數把一個字符串從一個位置複製到另一個位置,而strcat函數把一個字符串的一份拷貝添加到另一個字符串的後面。這兩個函數都假定它們的參數是有效的字符串,而且如果源字符串和目標字符串出現重疊,函數的結果是未定義的。strcmp對兩個字符串進行詞典序的比較。它的返回值提示第1個字符串是大於、小1還是等於第2個字符串。

    長度受限的函數strncpy, strncat和 strncmp都類似它們對應的不受限制版本,區別在於這些函數還接受一個長度參數。在strncpy中,長度指定了多少個字符將被寫入到目標字符數組中。如果源字符串比指定長度更長,結果字符串將不會以NUL字節結尾。strncat函數的長度參數指定從源字符串複製過來的字符的最大數目,但它的結果始終以一個NUL字節結尾, strcmp函數的K度參數用於限定字符比較的數目。如果兩個字符串在指定的數日裏不存在區別,它們便被認爲是相等的。

    用於查找字符串的函數有好幾個. strchr函數查找一個字符申中某個字符第1次出現的位置。strrchr函數查找一個字符串中某個字符最後-次出現的位置。strpbrk在一個字符串4查找一個指定字符集中任意字符第1次出現的位置。strstr函數在一個字符串中查找另一個字符申第1次出現的位置。

    標準庫還提供了了一些更高級的字符串查找函數。strspn函數計算一個字符串中第一個不在指定字符集出現的字符下標。strtok函數把一個字符串分隔成幾個部分,每次調用它都返回一個指向下一個標記位置的指針。

    sterror把一個錯誤碼作爲它的參數。它返回一個指向字符串的指針,該字符串用於描述這個錯誤。

    標準庫還提供了檢驗和轉換字符的函數。具體查表。

    memxxx函數提供了內存操作的功能。​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章