C-字符串诀诊、字符和字節(jié)(下)

06

高級(jí)字符串查找

? ? 接下來(lái)的一組函數(shù)簡(jiǎn)化了從一個(gè)字符串中查找和抽取一個(gè)子串的過(guò)程细办。

1.查找一個(gè)字符串前綴

? ? strspn和strcspn函數(shù)用于在字符串的起始位置對(duì)字符計(jì)數(shù)懒熙。它們的原型如下:

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

? ? group字符串指定一個(gè)或多個(gè)字符昼弟。strspn返回str第一個(gè)不在字符串 group中出現(xiàn)的字符下標(biāo)啤它。例如,如果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锣光。下面的代碼將計(jì)算第一個(gè)指向字符串中第一個(gè)非空白字符的指針。

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

? ? strcspn函數(shù)和strspn函數(shù)正好相反铝耻,它將返回第一個(gè)在group中的字符的下標(biāo)誊爹。strcspn這個(gè)詞中的字母c來(lái)源于對(duì)一組字符求補(bǔ)這個(gè)概念。

2.查找標(biāo)記

? ? 一個(gè)字符串常常包含了幾個(gè)有意義的部分瓢捉,它們被分隔符分隔開(kāi)來(lái)频丘。每次為了處理這些部分,你首先必須把它們從字符串中抽取出來(lái)泡态。

? ? 這個(gè)任務(wù)正是strtok函數(shù)所實(shí)現(xiàn)的功能搂漠。它從字符串中隔離各個(gè)單獨(dú)的稱為標(biāo)記(token)的部分,并丟棄分隔符某弦。它的原型如下:

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

? ? sep參數(shù)是個(gè)字符串桐汤,定義了用作分隔符的字符集合。第1參數(shù)指定一個(gè)字符串靶壮,它包含零個(gè)或多個(gè)由sep字符串中一個(gè)或多個(gè)分隔符分隔的標(biāo)記怔毛。strtok找到str的下一個(gè)標(biāo)記,并將其用NUL結(jié)尾腾降,然后返回一個(gè)指向這個(gè)標(biāo)記的指針拣度。若沒(méi)有可檢索的字符串,則返回一個(gè)空指針螃壤。

? ? 下面是一個(gè)簡(jiǎn)短的例子抗果,

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

? ? 編譯并運(yùn)行上面程序,這將產(chǎn)生以下結(jié)果:

This is

cxsjcrmdjt

official account

? ? 如果你愿意奸晴,你可以在每次調(diào)用strtok函數(shù)時(shí)使用不同的分隔符集合冤馏。當(dāng)一個(gè)字符串的不同部分由不同的字符集合分隔的時(shí)候,這個(gè)技巧很管用寄啼。

警告:

? ? 由于strtok函數(shù)保存它處理的函數(shù)的局部狀態(tài)信息宿接,所以你不能用它同時(shí)解析兩個(gè)字符串赘淮,因此,如果while循環(huán)體內(nèi)調(diào)用了一個(gè)在內(nèi)部調(diào)用strtok函數(shù)的函數(shù)睦霎,上述代碼將會(huì)失敗梢卸。

07

錯(cuò)誤信息

? ? 當(dāng)你調(diào)用一些函數(shù),請(qǐng)求操作系統(tǒng)執(zhí)行一些功能如打開(kāi)文件時(shí)副女,如果出現(xiàn)錯(cuò)誤蛤高,操作系統(tǒng)是通過(guò)設(shè)置一個(gè)外部的整型變量errno進(jìn)行錯(cuò)誤代碼報(bào)告的。strerror函數(shù)把其中一個(gè)錯(cuò)誤代碼作為參數(shù)并返回一個(gè)指向用于描述錯(cuò)誤的字符串的指針碑幅。這個(gè)函數(shù)的原型如下:

char *strerror(int error_number);

08

字符操作

? ? 標(biāo)準(zhǔn)庫(kù)包含了兩組函數(shù)戴陡,用于操作單獨(dú)的字符,它們的原型位于頭文件ctype.h沟涨。第一組函數(shù)用于對(duì)字符分類恤批,而第二組用于轉(zhuǎn)換字符。

1.字符分類

? ? 每個(gè)分類函數(shù)接受一個(gè)包含字符值的整型參數(shù)裹赴。函數(shù)測(cè)試這個(gè)字符并返回一個(gè)整型值喜庞,表示真或假。下表列出了這些分類函數(shù)以及它們每個(gè)所執(zhí)行的測(cè)試棋返。

?

2.字符串轉(zhuǎn)換

? ? 轉(zhuǎn)換函數(shù)可將大小寫(xiě)字母相互轉(zhuǎn)換延都。

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

? ? 如其函數(shù)名一樣,toupper函數(shù)返回對(duì)應(yīng)的大寫(xiě)形式睛竣,tolower函數(shù)返回對(duì)應(yīng)的小寫(xiě)形式晰房。如果函數(shù)的參數(shù)并不是一個(gè)可以大小寫(xiě)轉(zhuǎn)換的字符,函數(shù)將不修改參數(shù)直接返回射沟。

提示:

? ? 或許你會(huì)認(rèn)為這些函數(shù)的實(shí)現(xiàn)簡(jiǎn)單殊者,可以很輕易地被自己的實(shí)現(xiàn)替代,但是直接操控字符將會(huì)降低程序的可移植性验夯,考慮以下例子猖吴,它試圖測(cè)試ch是否是一個(gè)大寫(xiě)字符。

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

? ? 這條語(yǔ)句在使用ASCII字符集的機(jī)器上能夠運(yùn)行簿姨,但在使用EBCDIC字符集的機(jī)器上將會(huì)失敗距误。若使用下面這條語(yǔ)句:

if (isupper(ch))

? ? 無(wú)論機(jī)器使用哪種字符集簸搞,它都能順利執(zhí)行扁位。

09

內(nèi)存操作

? ? 根據(jù)定義,字符串由一個(gè)NUL字節(jié)結(jié)尾趁俊,所以字符串內(nèi)部不能包含任何NUL字符域仇。但是,非字符串?dāng)?shù)據(jù)內(nèi)部包含零值的情況并不罕見(jiàn)寺擂,你無(wú)法使用字符串函數(shù)來(lái)處理這種類型的數(shù)據(jù)暇务,因?yàn)楫?dāng)它們遇到第一個(gè)NUL字節(jié)時(shí)將停止工作泼掠。

? ? 不過(guò),我們可以使用另外一組相關(guān)的函數(shù)垦细,它們的作用于字符串函數(shù)類似择镇,但這些函數(shù)能夠處理任意的字節(jié)序列。下面是它們的原型括改。

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);

? ? 每個(gè)原型都包含一個(gè)顯式的參數(shù)說(shuō)明需要處理的字節(jié)數(shù)腻豌。但和strn開(kāi)頭的函數(shù)不同,它們?cè)谟龅絅UL字節(jié)時(shí)并不會(huì)停止操作嘱能。

? ? memcpy從src的起始位置復(fù)制length個(gè)字節(jié)到dst的內(nèi)存起始位置吝梅。你可以用這種方法復(fù)制任何類型的值,第三個(gè)參數(shù)指定復(fù)制值的長(zhǎng)度(以字節(jié)計(jì))惹骂。如果src和dst以任何形式出現(xiàn)了重疊苏携,它的結(jié)果是未定義的。

例如对粪,

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

? ? 它從數(shù)組values復(fù)制SIZE個(gè)字節(jié)到數(shù)組temp右冻。

? ? 但是,如果兩個(gè)數(shù)組都是整型數(shù)組該怎么辦衩侥?下面的語(yǔ)句可以完成這項(xiàng)任務(wù):

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

? ? 前兩個(gè)參數(shù)并不需要使用強(qiáng)制類型轉(zhuǎn)換国旷,因?yàn)樵诤瘮?shù)的原型中,參數(shù)的類型是void*型指針茫死,而任何類型的指針都可以轉(zhuǎn)換為void*型指針跪但。

? ? 如果數(shù)組只有部分內(nèi)容需要被復(fù)制,那么需要復(fù)制的數(shù)量必須在第三個(gè)參數(shù)中指明峦萎。對(duì)于長(zhǎng)度大于一個(gè)字節(jié)的數(shù)據(jù)屡久,要確保把數(shù)量和數(shù)據(jù)類型的長(zhǎng)度相乘,如:

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

? ? 你也可以使用這種技巧復(fù)制結(jié)構(gòu)體或者結(jié)構(gòu)體數(shù)組爱榔。

? ? memmove函數(shù)的行為和memcpy差不多被环,只是它的源和目的操作數(shù)可以重疊。雖然它不需要以下面這種方式實(shí)現(xiàn)详幽,不過(guò)memmove的過(guò)程和這種方法的過(guò)程相同:把源操作數(shù)復(fù)制到一個(gè)臨時(shí)位置筛欢,這個(gè)臨時(shí)位置不會(huì)與源或目標(biāo)操作數(shù)重疊,然后再把它從這個(gè)臨時(shí)位置復(fù)制到目標(biāo)操作數(shù)唇聘。memmove通常無(wú)法使用某些機(jī)器所提供的特殊的字節(jié)-字符串處理指令來(lái)實(shí)現(xiàn)版姑,所以它可能比memcpy慢一些。但是迟郎,如果源和目標(biāo)參數(shù)真的可能存在重疊剥险,就應(yīng)該使用memmove。

? ? memcmp對(duì)兩端內(nèi)存的內(nèi)容進(jìn)行比較宪肖,這兩端內(nèi)存分別起始于a和b表制,共比較length個(gè)字節(jié)健爬。這些值按照無(wú)符號(hào)字符逐字節(jié)進(jìn)行比較,函數(shù)的返回類型和strcmp函數(shù)一樣----負(fù)值表示a小于b么介,正值表示a大于b娜遵,零表示a等于b。由于這些值是根據(jù)一串無(wú)符號(hào)字節(jié)進(jìn)行比較的壤短,所以如果memcmp函數(shù)用于比較不是單字節(jié)的數(shù)據(jù)如整數(shù)或浮點(diǎn)數(shù)時(shí)可能會(huì)出現(xiàn)不可預(yù)料的結(jié)果魔熏。

? ? memchr從a的起始位置開(kāi)始查找字符ch第一次出現(xiàn)的位置,并返回一個(gè)指向該位置的指針鸽扁,它共查找length個(gè)字節(jié)蒜绽。如果在這length個(gè)字節(jié)中未找到該字符,函數(shù)就返回一個(gè)NULL指針桶现。

? ? memset函數(shù)把從a開(kāi)始的length個(gè)字節(jié)都設(shè)置為值ch躲雅。如:

memset(buffer,?0,?SIZE);

? ? 把buffer的前SIZE個(gè)字節(jié)都初始化為0。

10

總結(jié)

? ? 字符串就是零個(gè)或多個(gè)字符的序列骡和。該序列以一個(gè)NUL字節(jié)結(jié)尾相赁,字符串的長(zhǎng)度就是它所包含的字符的數(shù)目。標(biāo)準(zhǔn)庫(kù)提供了處理字符串的函數(shù)慰于,它們的原型位于頭文件string.h中钮科。

? ? strlen函數(shù)用于計(jì)算一個(gè)字符串的長(zhǎng)度,它的返回值是一個(gè)無(wú)符號(hào)整數(shù)婆赠,所以把它用于表達(dá)式時(shí)應(yīng)該小心绵脯。strcpy函數(shù)把一個(gè)字符串從一個(gè)位置復(fù)制到另一個(gè)位置,而strcat函數(shù)把一個(gè)字符串的一份拷貝添加到另一個(gè)字符串的后面休里。這兩個(gè)函數(shù)都假定它們的參數(shù)是有效的字符串,而且如果源字符串和目標(biāo)字符串出現(xiàn)重疊,函數(shù)的結(jié)果是未定義的蛆挫。strcmp對(duì)兩個(gè)字符串進(jìn)行詞典序的比較。它的返回值提示第1個(gè)字符串是大于妙黍、小1還是等于第2個(gè)字符串悴侵。

? ? 長(zhǎng)度受限的函數(shù)strncpy, strncat和 strncmp都類似它們對(duì)應(yīng)的不受限制版本,區(qū)別在于這些函數(shù)還接受一個(gè)長(zhǎng)度參數(shù)。在strncpy中,長(zhǎng)度指定了多少個(gè)字符將被寫(xiě)入到目標(biāo)字符數(shù)組中拭嫁。如果源字符串比指定長(zhǎng)度更長(zhǎng),結(jié)果字符串將不會(huì)以NUL字節(jié)結(jié)尾可免。strncat函數(shù)的長(zhǎng)度參數(shù)指定從源字符串復(fù)制過(guò)來(lái)的字符的最大數(shù)目,但它的結(jié)果始終以一個(gè)NUL字節(jié)結(jié)尾, strcmp函數(shù)的K度參數(shù)用于限定字符比較的數(shù)目。如果兩個(gè)字符串在指定的數(shù)日里不存在區(qū)別,它們便被認(rèn)為是相等的做粤。

? ? 用于查找字符串的函數(shù)有好幾個(gè). strchr函數(shù)查找一個(gè)字符申中某個(gè)字符第1次出現(xiàn)的位置浇借。strrchr函數(shù)查找一個(gè)字符串中某個(gè)字符最后-次出現(xiàn)的位置。strpbrk在一個(gè)字符串4查找一個(gè)指定字符集中任意字符第1次出現(xiàn)的位置驮宴。strstr函數(shù)在一個(gè)字符串中查找另一個(gè)字符申第1次出現(xiàn)的位置逮刨。

? ? 標(biāo)準(zhǔn)庫(kù)還提供了了一些更高級(jí)的字符串查找函數(shù)呕缭。strspn函數(shù)計(jì)算一個(gè)字符串中第一個(gè)不在指定字符集出現(xiàn)的字符下標(biāo)堵泽。strtok函數(shù)把一個(gè)字符串分隔成幾個(gè)部分修己,每次調(diào)用它都返回一個(gè)指向下一個(gè)標(biāo)記位置的指針。

? ? sterror把一個(gè)錯(cuò)誤碼作為它的參數(shù)迎罗。它返回一個(gè)指向字符串的指針睬愤,該字符串用于描述這個(gè)錯(cuò)誤。

? ? 標(biāo)準(zhǔn)庫(kù)還提供了檢驗(yàn)和轉(zhuǎn)換字符的函數(shù)纹安。具體查表尤辱。

? ? memxxx函數(shù)提供了內(nèi)存操作的功能。?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厢岂,一起剝皮案震驚了整個(gè)濱河市光督,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌塔粒,老刑警劉巖结借,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異卒茬,居然都是意外死亡船老,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)圃酵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)柳畔,“玉大人,你說(shuō)我怎么就攤上這事郭赐⌒胶” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵捌锭,是天一觀的道長(zhǎng)躬存。 經(jīng)常有香客問(wèn)我,道長(zhǎng)舀锨,這世上最難降的妖魔是什么岭洲? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮坎匿,結(jié)果婚禮上盾剩,老公的妹妹穿的比我還像新娘。我一直安慰自己替蔬,他們只是感情好告私,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著承桥,像睡著了一般驻粟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天蜀撑,我揣著相機(jī)與錄音挤巡,去河邊找鬼。 笑死酷麦,一個(gè)胖子當(dāng)著我的面吹牛矿卑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沃饶,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼母廷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了糊肤?” 一聲冷哼從身側(cè)響起琴昆,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎馆揉,沒(méi)想到半個(gè)月后椎咧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡把介,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年勤讽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拗踢。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡脚牍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巢墅,到底是詐尸還是另有隱情诸狭,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布君纫,位于F島的核電站驯遇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蓄髓。R本人自食惡果不足惜叉庐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望会喝。 院中可真熱鬧陡叠,春花似錦、人聲如沸肢执。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)预茄。三九已至兴溜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拙徽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工刨沦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斋攀。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像梧田,于是被迫代替她去往敵國(guó)和親淳蔼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容