C語(yǔ)言字符串函數(shù)介紹與模擬實(shí)現(xiàn)詳解
1. strlen(求字符串長(zhǎng)度)
這個(gè)函數(shù)就是求一個(gè)字符串的長(zhǎng)度。
注意它是不算'\0'的,即以'\0'為結(jié)束標(biāo)志,計(jì)算其之前的字符串長(zhǎng)度,但不能沒(méi)有'\0'.
讓我們來(lái)一個(gè)有趣的例子:
int main() { if (strlen("abc") - strlen("abcdef")) printf("hehe"); else printf("haha"); return 0; }
以上的代碼乍一眼看是3 - 6 = -3,應(yīng)該輸出haha
但是strlen函數(shù)返回的是無(wú)符號(hào)整型,所以-3被看作無(wú)符號(hào)整數(shù),應(yīng)該是一個(gè)大于0的數(shù)。
1.1 strlen 模擬實(shí)現(xiàn)
那么這個(gè)函數(shù)自己來(lái)寫應(yīng)該怎樣實(shí)現(xiàn)呢?
模擬實(shí)現(xiàn)需要考慮到所有情況:
所以 const 防止改變字符串與 assert 防止傳入空指針不可少。
size_t my_strlen(const char* a) { assert(a); int count = 0; while (*a) { count++; a++; } return count; }
2. strcpy(復(fù)制字符串)
這個(gè)函數(shù)用于把一個(gè)字符串內(nèi)容賦給另一個(gè)字符串內(nèi),如果目的字符串有內(nèi)容,直接覆蓋。
注意點(diǎn):strcpy復(fù)制字符串從arr2到arr1
被復(fù)制的字符串一定要帶'\0',因?yàn)檫@個(gè)是結(jié)束標(biāo)志
目標(biāo)空間也要足夠大且可變(可變:用數(shù)組寫,而非指針卡死)
int main() { char arr1[] = "xxxxxxxxxxxxxxx"; //char *p = "xxx";//不可變且空間小 char arr2[] = "abcd\0efg"; strcpy(arr1, arr2); printf("%s", arr1); return 0; }
2.1 strncpy函數(shù)
這個(gè)函數(shù)是不是很相像?由于strcpy 直接將一個(gè)字符串完全復(fù)制過(guò)去,
那么有沒(méi)有一個(gè)函數(shù)能只復(fù)制一部分呢?此函數(shù)就是充當(dāng)這個(gè)作用的。
它將 num 個(gè)字符從源字符串中取出,放入目的字符串。
int main() { char a[] = "abcde"; char b[] = "abc"; strncpy(a, b, 6); printf("%s", a); return 0; }
如果遇到源字符串不夠的情況,會(huì)自動(dòng)補(bǔ)0.
2.2 模擬實(shí)現(xiàn)strcpy
char* my_strcpy(char* a1, const char* a2)//原指針被修改,不加const { assert(a1 && a2); char* ret = a1; while (*a1++ = *a2++) { ; } return ret; }
來(lái)解釋一下這個(gè)寫法(*a1++ = *a2++ ):
先把a(bǔ)2賦給a1,然后各自++。當(dāng)a2為0時(shí),這個(gè)表達(dá)式值為0,就退出循環(huán)。
因?yàn)橹捣旁诘刂穬?nèi),所以a1的地址給ret存好后,最后返回ret的地址就是返回a1的值.
3. strcat (追加字符)
傳入兩個(gè)字符串,將后一個(gè)字符串追加到前一個(gè)字符串上。
源字符串必須要有 '\0' 作為結(jié)束標(biāo)志,且目標(biāo)字符串足夠大且可變。(提前定義目標(biāo)數(shù)組大?。?/p>
如果需要自己給自己追加,那么就使用這個(gè)函數(shù)。
3.1 strncat 函數(shù)
就是將源字符串 num 個(gè)字符追加到目標(biāo)字符串上,如下圖:
3.2 模擬實(shí)現(xiàn)strcat
char* my_strcat(char* a, const char* b) { assert(a && b); char* p = a; //先找到a字符串為'\0'的位置 while (*a) { a++; } while (*a++ = *b++) { ; } return p; }
4. strcmp(比較兩個(gè)字符串內(nèi)容)
傳入兩個(gè)字符串,比較兩個(gè)字符串。
str1 > str2 返回正數(shù); = 返回0; < 返回負(fù)數(shù)
那么是怎么比較的呢?
記住是比較不相同的那個(gè)字符大小,跟長(zhǎng)度沒(méi)有一點(diǎn)關(guān)系。
如圖就是比較 'e' 和 'q' 的字符大小,明顯 'q' 更大,所以返回 -1.
4.1 strncmp函數(shù)
和strncpy相似,就是將兩個(gè)字符串前num個(gè)字符比較,規(guī)則同 strcmp 函數(shù) 。
4.2 模擬實(shí)現(xiàn)strcmp
int my_strcmp(const char* a, const char* b) { assert(a && b); while (*a == *b) { if (*b == '\0') return 0; a++; b++; } /*if (*a > *b) return 1; if (*a < *b) return -1;*/ return *a - *b;//這樣一步到位 }
5. strstr (返回str1出現(xiàn)在str2位置處第一次的指針)
就是返回b字符串在a中第一次出現(xiàn)的位置的指針,如下就會(huì)打印 am a student.
如果沒(méi)有找到就返回空指針。
int main() { char a[] = "I am a student."; char b[] = "am"; printf("%s", strstr(a, b)); return 0; }
5.1 模擬實(shí)現(xiàn)strstr
char* my_strstr(const char* str1, const char* str2) { assert(str1 && str2); char* s1; char* s2; char* cp = str1; if (*str2 == '\0')//如果傳入了"" return str1; while (*cp) { s1 = cp; s2 = str2; while (*s1 == *s2 && *s1 && *s2) { s1++; s2++; } if (*s2 == '\0') { return cp; } cp++; } return NULL; }
6. strtok(分割字符串)
這個(gè)函數(shù)能以我們所需分割字符串,sep是分割的標(biāo)志,str是被分割的字符串。
下面來(lái)一個(gè)例子:
int main() { char a[] = "123@qq.com"; char b[] = "@."; printf("%s\n", strtok(a, b));//分割了123 printf("%s\n", strtok(NULL, b));//分割了qq printf("%s\n", strtok(NULL, b));//分割了com return 0; }
第一次分割完,之后這個(gè)函數(shù)會(huì)記住分割的位置,把目標(biāo)函數(shù)的分割標(biāo)志變?yōu)?\0'
所以這個(gè)函數(shù)會(huì)修改字符串,要小心使用。
下次使用只需要傳入空指針,這是這個(gè)函數(shù)的重點(diǎn)。
我們也可以使用循環(huán)來(lái)表達(dá)它的結(jié)果:
int main() { char *p = "666@qq.com"; const char* sep = ".@"; char arr[30]; char *str = NULL; strcpy(arr, p);//將數(shù)據(jù)拷貝一份,處理arr數(shù)組的內(nèi)容 for(str=strtok(arr, sep); str != NULL; str=strtok(NULL, sep)) { printf("%s\n", str); } }
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Matlab實(shí)現(xiàn)帶豎線散點(diǎn)的核密度圖的繪制
核密度估計(jì)是用于估計(jì)隨機(jī)變量概率密度函數(shù)的一種非參數(shù)方法。核密度圖不失為一種用來(lái)觀察連續(xù)型變量分布的有效方法。本文將用Matlab實(shí)現(xiàn)帶豎線散點(diǎn)的核密度圖的繪制,感興趣的可以了解一下2022-08-08一個(gè)string類的簡(jiǎn)單實(shí)現(xiàn)案例
下面小編就為大家?guī)?lái)一篇一個(gè)string類的簡(jiǎn)單實(shí)現(xiàn)案例。小編覺(jué)得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01c++中移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā)及易錯(cuò)點(diǎn)
C++ 中的移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā)是 C++11 引入的兩個(gè)重要特性,它們分別用于提高性能和靈活性,這篇文章主要介紹了c++中移動(dòng)語(yǔ)義和完美轉(zhuǎn)發(fā),需要的朋友可以參考下2023-09-09C++實(shí)現(xiàn)學(xué)生宿舍管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)學(xué)生宿舍管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03詳細(xì)解析命令行的getopt_long()函數(shù)
getopt_long支持長(zhǎng)選項(xiàng)的命令行解析,函數(shù)中的參數(shù)argc和argv通常直接從main()的兩個(gè)參數(shù)傳遞而來(lái)2013-09-09C++實(shí)現(xiàn)二分法求連續(xù)一元函數(shù)根
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)二分法求連續(xù)一元函數(shù)根,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06C++實(shí)現(xiàn)LeetCode(148.鏈表排序)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(148.鏈表排序),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07