C-字符串咱筛、字符和字節(jié)(上)

字符串是一種重要的數(shù)據(jù)類型,但是C語(yǔ)言并沒(méi)有顯式的字符串?dāng)?shù)據(jù)類型作儿,因?yàn)樽址宰址A康男问匠霈F(xiàn)或者存儲(chǔ)于字符數(shù)組中。字符串常量適用于那些程序不會(huì)進(jìn)行修改的字符串馋劈。所有其他字符串必須存儲(chǔ)于字符數(shù)組或動(dòng)態(tài)分配的內(nèi)存中攻锰。本文描述處理字符串和字符的庫(kù)函數(shù),以及一些相關(guān)的妓雾,具有類似能力的函數(shù)娶吞。

01

字符串基礎(chǔ)

首先,我們了解下字符串的基礎(chǔ)知識(shí)械姻。字符串就是一串零個(gè)或多個(gè)字符妒蛇,并且以一個(gè)位模式為全0的NUL字節(jié)結(jié)尾。因此楷拳,字符串包含的字符內(nèi)部不能出現(xiàn)NUL字節(jié)绣夺。這個(gè)限制很少會(huì)引起問(wèn)題,因?yàn)镹UL字節(jié)并不存在與它相關(guān)聯(lián)的可打印字符欢揖,這也是它被選為終止符的原因陶耍。NUL字節(jié)是字符串的終止符,但它本身并不是字符串的一部分浸颓,所以字符串的長(zhǎng)度并不包括NUL字節(jié)物臂。

02

字符串的長(zhǎng)度

字符串的長(zhǎng)度就是它所包含的字符個(gè)數(shù)旺拉。我們很容易通過(guò)對(duì)字符進(jìn)行計(jì)數(shù)來(lái)計(jì)算字符串的長(zhǎng)度,下面程序就是這樣做的棵磷。

#include <stddef.h>size_t strlen(char const *string){????int?length;????for?(length?=?0;?*string++?!=?'\0';?)????? ? length += 1;????return?length;}

這種實(shí)現(xiàn)方法說(shuō)明了處理字符串所使用的的處理過(guò)程的類型蛾狗。但是,事實(shí)上你極少需要編寫(xiě)字符串函數(shù)仪媒,因?yàn)闃?biāo)準(zhǔn)庫(kù)所提供的函數(shù)通常能完成這些任務(wù)沉桌。不過(guò),如果你還是希望自己編寫(xiě)一個(gè)字符串函數(shù)算吩,請(qǐng)注意標(biāo)準(zhǔn)保留了所有以str開(kāi)頭的函數(shù)名留凭,用于標(biāo)準(zhǔn)庫(kù)將來(lái)的拓展。

03

不受限制的字符串函數(shù)

最常用的字符串函數(shù)都是“不受限制”的偎巢,就是說(shuō)它們只是通過(guò)尋找字符串參數(shù)結(jié)尾的NUL字節(jié)來(lái)判斷它的長(zhǎng)度蔼夜。這些函數(shù)一般都指定一塊內(nèi)存用于存放結(jié)果字符串。在使用這些函數(shù)時(shí)压昼,程序員必須保證結(jié)果字符串不會(huì)溢出這塊內(nèi)存求冷。這節(jié)將做詳細(xì)討論。

復(fù)制字符串

????用于復(fù)制字符串的函數(shù)是strcpy窍霞,它的原型如下所示:


char?*strcpy(char *dst, char const *src);

這個(gè)函數(shù)把參數(shù)src字符串復(fù)制到dst參數(shù)匠题,如果src和dst在內(nèi)存中出現(xiàn)重疊,其結(jié)果是未定義的但金。由于dst參數(shù)將進(jìn)行修改韭山,所以它必須是個(gè)字符數(shù)組或者是一個(gè)指向動(dòng)態(tài)分配內(nèi)存的指針,不能使用字符串常量冷溃。

目標(biāo)參數(shù)的的以前內(nèi)容將被覆蓋并丟失钱磅。即使新的字符串比dst原先的內(nèi)存更短,由于新字符串是以NUL字節(jié)結(jié)尾的似枕,所以老字符串最后剩余的幾個(gè)字符也會(huì)被有效地刪除续搀。

char?messgae[]?=?"Original?messgae";...strcpy(message,?"Different");

順利執(zhí)行strcpy之后,數(shù)組將包含下面內(nèi)容:

|'D'|'i'|'f'|'e'|'r'|'e'|'n'|'t'|0|'e'|'s'|'s'|'a'|'g'|'e'|0|

第一個(gè)NUL字節(jié)后面的幾個(gè)字符無(wú)法被字符串函數(shù)訪問(wèn)菠净,因此從實(shí)際角度來(lái)看,它們已經(jīng)是丟失的了彪杉。

警告:

你必須保證目標(biāo)字符數(shù)組的空間足以容納需要復(fù)制的字符串毅往,如果字符串比數(shù)組長(zhǎng),多余的字符仍被復(fù)制派近,它們將覆蓋原先存儲(chǔ)于數(shù)組后面的內(nèi)存空間的值攀唯,strcpy無(wú)法解決這個(gè)問(wèn)題,因?yàn)樗鼰o(wú)法判斷目標(biāo)字符數(shù)組的長(zhǎng)度渴丸。例如:

char message[] = "Original messgae";...strcpy(message, "A different message");

第二個(gè)字符串太長(zhǎng)了侯嘀,無(wú)法容納于message數(shù)組中另凌。因此,strcpy函數(shù)將侵占數(shù)組后面的部分內(nèi)存空間戒幔,改寫(xiě)原先恰好存儲(chǔ)在那里的變量吠谢。如果你在使用這個(gè)函數(shù)前確保目標(biāo)函數(shù)足以容納源字符串,就可以避免大量調(diào)試工作诗茎。

2.連接字符串

要想把一個(gè)字符串添加(連接)到另一個(gè)字符串的后面工坊,你可以使用strcat函數(shù)。它的原型如下:

char?*strcat(char?*dst,?char?const *src);

strcat要求dst參數(shù)原先已經(jīng)包含了一個(gè)字符串(可以是空字符串)敢订,它找到這個(gè)字符串的末尾王污,并把src字符串的一份拷貝添加到這個(gè)位置。如果src和dst的位置發(fā)生重疊楚午,其結(jié)果是未定義的昭齐。

下面是它的常見(jiàn)用法,

char?name[]?=?"Jim";strcpy(message, "Hello ");strcat(message, name);strcat(message,?",?how are you?");

每個(gè)strcat函數(shù)的字符串參數(shù)都被添加到原先存于message數(shù)組的字符串后面矾柜,其結(jié)果是下面這個(gè)字符串:

Hello Jim阱驾, how are you?

3.函數(shù)的返回值

strcpy和strcat都返回它們第一個(gè)參數(shù)的一份拷貝把沼,就是一個(gè)指向目標(biāo)字符數(shù)組的指針啊易,由于它們都是返回這種類型的值,所以你可以嵌套地調(diào)用這些函數(shù)饮睬,如下所示:

strcat(strcpy(dst, a), b);

strcpy首先執(zhí)行租谈。它把字符串從a復(fù)制到dst并返回dst。然后這個(gè)返回值稱為strcat函數(shù)的第一個(gè)參數(shù)捆愁,strcat把b添加到dst后面割去。

這種嵌套調(diào)用的風(fēng)格較之下面這種可讀性更佳的風(fēng)格在功能上并無(wú)優(yōu)勢(shì)。

strcpy(dst, a);strcat(dst, b);

事實(shí)上昼丑,這些函數(shù)的的絕大多數(shù)調(diào)用中呻逆,它們的返回值只是被簡(jiǎn)單地忽略。

4.字符串比較

比較兩個(gè)字符串涉及對(duì)兩個(gè)字符串對(duì)應(yīng)的字符逐個(gè)比較菩帝,直到發(fā)現(xiàn)不匹配為止咖城。那個(gè)最先不匹配的字符中較“小”(在字符集中的序數(shù)較小)的那個(gè)字符所在的字符串被認(rèn)為小于另外一個(gè)字符串呼奢。如果其中一個(gè)字符串是另一個(gè)字符串的前面一部分宜雀,那么它也被認(rèn)為小于另外一個(gè)字符串,因?yàn)樗腘UL結(jié)尾字節(jié)出現(xiàn)得更早握础。這種比較被稱為“詞典比較”辐董,對(duì)于只包含大寫(xiě)字母或只包含小寫(xiě)字母的字符比較,這種比較過(guò)程所給出的結(jié)果總是和我們?nèi)粘K玫淖帜疙樞虻谋容^相同禀综。

庫(kù)函數(shù)strcmp用于比較兩個(gè)字符串简烘,它的原型如下:

int strcmp(char const *s1, char const *s2);

如果s1小于s2苔严,函數(shù)返回一個(gè)小于零的值,如果s1大于s2孤澎,函數(shù)返回一個(gè)大于零的值届氢。如果兩個(gè)字符串相等,函數(shù)就返回零亥至。

04

長(zhǎng)度受限的字符串函數(shù)

標(biāo)準(zhǔn)庫(kù)還包含了一些函數(shù)悼沈,它們以一種不同的方式處理字符串。這些函數(shù)接受一個(gè)顯式的長(zhǎng)度參數(shù)姐扮,用于限定進(jìn)行復(fù)制或比較的字符數(shù)絮供。這些函數(shù)提供了一種方便的機(jī)制,可以防止難以預(yù)料的長(zhǎng)字符從它們的目標(biāo)數(shù)組溢出茶敏。

這些函數(shù)的原型如下壤靶,和它們不受限制的版本一樣,如果源參數(shù)與目標(biāo)參數(shù)發(fā)生重疊惊搏,strncpy和strncat的結(jié)果就是未定義的贮乳。

char?*strncpy(char?*dst,?char?const?*src,?size_t?len);char?*strncat(char?*dst,?char?const?*src,?size_t len);int?strncmp(char?const *s1, char const *s2, size_t len);

和strcpy一樣,strncpy把源字符串的字符復(fù)制到目標(biāo)數(shù)組恬惯。然而向拆,它總是正好向dst寫(xiě)入len個(gè)字符。如果strlen(src)的值小于len酪耳,dst就用額外的NUL字符填充到len長(zhǎng)度浓恳。如果strlen(src)的值大于等于len,那么只有l(wèi)en個(gè)字符被復(fù)制到dst中碗暗。注意颈将!它的結(jié)果將不會(huì)以NUL字節(jié)結(jié)尾。

警告:

strncpy調(diào)用的結(jié)果可能不是一個(gè)字符串言疗,因?yàn)樽址仨氁訬UL字節(jié)結(jié)尾晴圾。如果在一個(gè)需要字符串的地方(如strlen函數(shù)的參數(shù))使用了一個(gè)不是以NUL字節(jié)結(jié)尾的字符序列,會(huì)發(fā)生什么情況呢噪奄?strlen函數(shù)將無(wú)法知道NUL字節(jié)是沒(méi)有的死姚,所以它會(huì)繼續(xù)查找,直到它發(fā)現(xiàn)一個(gè)NUL字節(jié)為止勤篮≈剩或許找了幾百個(gè)字符才找到,而strlen函數(shù)的這個(gè)返回值從本質(zhì)上說(shuō)是一個(gè)隨機(jī)數(shù)叙谨。或者保屯,如果函數(shù)試圖訪問(wèn)系統(tǒng)分配給這個(gè)程序以外的內(nèi)存范圍手负,程序就會(huì)崩潰涤垫。

盡管strncat也是一個(gè)長(zhǎng)度受限的函數(shù),但它和strncpy存在不同之處竟终。它從src中最多復(fù)制len個(gè)字符到目標(biāo)數(shù)組后面蝠猬。但是,strncat總是在結(jié)果字符串后面添加一個(gè)NUL字節(jié)统捶,且它不會(huì)像strncpy那樣對(duì)目標(biāo)數(shù)組用NUL字節(jié)進(jìn)行填充榆芦。注意目標(biāo)數(shù)組中原先的字符串并沒(méi)有算在strncat的長(zhǎng)度中。strncat最多向目標(biāo)數(shù)組復(fù)制len個(gè)字符(再加一個(gè)結(jié)尾的NUL字節(jié))喘鸟,它不會(huì)管目標(biāo)參數(shù)除去原先字符串后剩下的空間夠不夠匆绣。

最后,strncmp也用于比較兩個(gè)字符串什黑,但它最多比較len個(gè)字節(jié)崎淳。如果兩個(gè)字符串在第len個(gè)字符之前存在不相等的字符,這個(gè)函數(shù)就像strcmp一樣停止比較愕把,返回結(jié)果拣凹。如果兩個(gè)字符串的前l(fā)en個(gè)字符相等,函數(shù)就返回零恨豁。

05

字符串查找

標(biāo)準(zhǔn)庫(kù)中存在許多函數(shù)嚣镜,它們用各種不同的方法查找字符串。這樣各種各樣的工具給了碼手很大的靈活性橘蜜。

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

在一個(gè)字符串中查找一個(gè)特定字符最容易的方法是使用strchr和strrchr函數(shù)菊匿,它們的原型如下:

char *strchr(char const *str, int ch);char?*strrchr(char const *str, int ch);

注意它們的第2個(gè)參數(shù)是一個(gè)整型值。但是扮匠,它包含了一個(gè)字符值捧请。strchr在字符串str中查找字符ch第1次出現(xiàn)的位置,找到后函數(shù)返回一個(gè)指向該位置的指針棒搜。如果該字符串中不存在該字符疹蛉,函數(shù)就返回一個(gè)NULL指針。strrchr的功能和strchr基本一致力麸,只是它返回的是一個(gè)指向該字符串該字符最后一次出現(xiàn)的位置可款。

2.查找任何幾個(gè)字符

strpbrk是個(gè)更為常見(jiàn)的函數(shù)。它并不是查找某個(gè)特定的字符克蚂,而是查找任何一組字符第一次在字符串中出現(xiàn)的位置闺鲸。它的原型如下:

char *strpbrk(char const *str, char const *group);

這個(gè)函數(shù)返回一個(gè)指向str中第一個(gè)匹配group中任何一個(gè)字符的字符位置。如果未找到匹配埃叭,函數(shù)返回一個(gè)NULL指針摸恍。

如下代碼:

char?string[20]?=?"Hello?there,?honey.";char *ans;ans?=?strpbrk(string,?"aeiou");

ans指向的位置是string+1,因?yàn)檫@個(gè)位置是第二個(gè)參數(shù)中的字符第一次出現(xiàn)的位置。和前面一樣立镶,這個(gè)函數(shù)也是區(qū)分大小寫(xiě)的壁袄。

3.查找一個(gè)子串

為了在字符串中查找一個(gè)子串,可以使用strstr函數(shù)媚媒,它的原型如下:

char?*strstr(char?const?*s1,?char const *s2);

這個(gè)函數(shù)s1中查找整個(gè)s2第一次出現(xiàn)的起始位置嗜逻,并返回一個(gè)指向該位置的指針。如果s2并沒(méi)有完整地出現(xiàn)在s1的任何地方缭召,函數(shù)將返回一個(gè)NULL指針栈顷。如果第二個(gè)參數(shù)是一個(gè)空字符串,函數(shù)就返回s1嵌巷。

標(biāo)準(zhǔn)庫(kù)中并不存在strrstr和strrpbrk萄凤。不過(guò),如果你需要它們晴竞,它們是很容易實(shí)現(xiàn)的蛙卤。

?著作權(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)容