C語言中字符串庫函數(shù)的實現(xiàn)及模擬
前言
我們已經(jīng)了解了C語言中很多數(shù)據(jù)類型,比如int(整數(shù)類型)、char(字符類型)、以及浮點型的double(雙精度)、float(單精度),但是有一點就是我們發(fā)現(xiàn)這里并沒有提到我們常見的有關(guān)字符串的類型。其實在C語言中,字符串通常是放在 常量字符串 中或者 字符數(shù)組 中的。(常量字符串是不可被修改的)
1.strlen的實現(xiàn)及模擬(求字符串長度)
字符串是雙引號" "引起來的,以 ‘\0’ 作為結(jié)束標(biāo)志,strlen是專門用來求字符串長度的,strlen函數(shù)返回的是在字符串中 ‘\0’ 前面出現(xiàn)的字符個數(shù)(不包含 ‘\0’ )。并且返回值必須是正數(shù),因為字符個數(shù)不存在負(fù)數(shù)情況!

使用以及模擬實現(xiàn)
#include<stdio.h>//printf頭文件
#include<string.h>//strlen頭文件
#include<assert.h>//assert頭文件
//返回值為無符號類型(正數(shù))
//模擬實現(xiàn),這里盡量做到還原原函數(shù)的形式
size_t my_strlen(const char* str)
{
assert(str);//斷言,如果str是NULL,編譯器報錯
const char* start = str;//首字符地址賦給start以及end
const char* end = str;
while (*end != '\0')//當(dāng)end指向'\0'時結(jié)束
{
end++;
}
return end - start;//指針相減得到兩者之間元素個數(shù)
}
int main()
{
char arr[] = "abcdef";
printf("%d\n", strlen(arr));//arr是數(shù)組名,表示數(shù)組首元素地址,即a的地址,返回值為\0之前的字符個數(shù),即6
int len=my_strlen(arr);
printf("%d\n", len);//6
return 0;
}
這里我是采用指針-指針=兩指針之間元素個數(shù)的方式,還有很多方式都可以模擬實現(xiàn),比如創(chuàng)建一個變量計數(shù)的方式等,如下:
size_t my_strlen(const char * str)
{
assert(str);//斷言
size_t count = 0;//無符號
while(*str)
{
count++;//指針從起始位置開始往前走,每走一次count++一次
str++;
}
return count;//最后返回count
}
2.strcmp的實現(xiàn)及模擬 (字符串比較)
strcmp是用來比較兩個字符串的。兩個字符串比較的其實是各字符所對應(yīng)的ASCII碼值,如下:

使用以及模擬實現(xiàn)
#include<string.h>//strcpy頭文件包含
#include<stdio.h>//printf頭文件包含
#include<assert.h>//斷言
int my_strcmp(const char* s1, const char* s2)
{
assert(s1 && s2);//斷言
while (*s1 == *s2)//如果兩個字符串中對應(yīng)的字符相等,則繼續(xù)往后找
{
if (*s1 == '\0')//當(dāng)s1到\0時,說明s2也是\0,字符串直到結(jié)束,兩者都相等
return 0;//返回0
//如果沒到\0,繼續(xù)往后走,進(jìn)行下一個字符比較
s1++;
s2++;
}
//當(dāng)跳出循環(huán)時,說明s1與s2指向的字符不相等,直接返回兩者之差即可
return *s1 - *s2;
//*s1 -*s2>0 即 *s1>*s2,即字符數(shù)組arr1中的字符串>arr2中的
//反之則小于
}
int main()
{
//字符串存放在字符數(shù)組
char arr1[] = "abcdeaf";
char arr2[] = "abcdef";
//模擬實現(xiàn)
int len=my_strcmp(arr1, arr2);
//strcmp兩個參數(shù),arr1,arr2數(shù)組名,即首元素地址,即字符串首字符地址
printf("%d\n", strcmp(arr1, arr2));//-5
printf("%d\n", len);//-5 a對應(yīng)ASCII:97 f:102
// 97-102 ==-5
return 0;
}
strncmp的實現(xiàn)及模擬
strncmp與strcmp很類似,也是用來比較兩個字符串的,唯一的區(qū)別就是strcmp是比較整個字符串,而strncmp可以指定比較的第多少個字符,比如說比較abcdef與abcdfg兩個字符串的前三個字符,結(jié)果返回值就是0。因為僅僅比較的是前三個字符,即abc。

模擬實現(xiàn)
#include<string.h>
#include<stdio.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);//斷言
//比較前num個字符,兩者相等時,進(jìn)入循環(huán),繼續(xù)往后比,num限制比較字符數(shù)
while (--num && (*str1) && (*str1 == *str2))
{
str1++;
str2++;
}
//跳出循環(huán),說明num比完了,或者有一方遇到\0,或者兩字符不相等
//直接返回兩者之差
return *str1 - *str2;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcbefgg";
int num = 0;
scanf("%d", &num);
//比較字符串a(chǎn)rr1與arr2的前num個字符
int len=my_strncmp(arr1, arr2,num);
//printf("%d\n", strncmp(arr1, arr2,3));//0
printf("%d\n", len);// num=3,len=0;num=4,len>0
return 0;
}
3.strcpy的實現(xiàn)及模擬(字符串拷貝)
strcpy是用來拷貝字符串的

注意事項
- !!! 源字符串必須以 ‘\0’ 結(jié)束。
- !!! 會將源字符串中的 ‘\0’ 拷貝到目標(biāo)空間。
- !!! 目標(biāo)空間必須足夠大,以確保能存放源字符串。
- !!! 目標(biāo)空間必須可變。
使用及模擬實現(xiàn)
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char*dest,char*src)
{
//斷言
assert(dest && src);
char* ret = dest;//用來記住arr的起始地址
while (*dest++ = *src++)//不斷地賦值,arr不斷地被覆蓋
{
;
}
//返回起始地址
return ret;
}
int main()
{
char arr[20] = "hello";
char* p = "abcdef";
//strcpy(arr, p);
//模擬實現(xiàn)
my_strcpy(arr, p);
printf("%s", arr);//abcdef
return 0;
}
strncpy的使用及模擬實現(xiàn)
strncpy與strcpy的使用相類似,但是strcpy是拷貝整個字符串,而strncpy是可以指定拷貝,即只拷貝num個字符,如果源字符串的長度小于num,則拷貝完源字符串之后,在目標(biāo)的后邊追加0,直到num個。

使用及模擬實現(xiàn)
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* sor, size_t num)
{
//斷言
assert(dest && sor);
char* s = dest;//起始地址記住
int i = 0;
for (i = 0; i < (int)num; i++)
{
//開始拷貝,num次,每次拷貝一個字符,拷貝完后,兩指針往后走,繼續(xù)拷貝
*dest++ = *sor++;
}
//返回起始地址
return s;
}
int main()
{
char arr1[20] = "abcdefghi";
char arr2[20] = "xxxx";
size_t n = 0;
scanf("%d", &n);
my_strncpy(arr1, arr2, n);
//從arr2中拷貝n個字符到arr1去
printf("%s", arr1);//n=4,xxxxefghi\0 ; n=5,xxxx\0fghi\0,但是打印的是xxxx,因為遇到\0字符串停止
return 0;
}
4.strcat的實現(xiàn)及模擬(字符串追加)
strcat是字符串追加函數(shù),顧名思義就是在一個字符串后面再增加另外一個字符串。
注意事項
- 源字符串必須以 ‘\0’ 結(jié)束。
- 目標(biāo)空間必須有足夠的大,能容納下源字符串的內(nèi)容。
- 目標(biāo)空間必須可修改。
- 不能自己給自己追加

實現(xiàn)及模擬
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
//斷言
assert(dest && src);
char* sur = dest;//記住起始地址
while (*sur != '\0')
{
sur++;
}
//走到這里,sur已經(jīng)指向了arr1的\0處,從這里開始,把src指向的字符即arr2的字符賦給sur
while (*sur++ = *src++)
{
;
}
//最后返回arr1追加后的起始空間地址
return dest;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "world";
//在arr1后面增加arr2
//strcat(arr1, arr2);
my_strcat(arr1, arr2);
printf("%s\n", arr1);//hello world
return 0;
}
strncat的使用及模擬實現(xiàn)
strncat與strcat很類似,只不過strcat是追加整個字符串,而strncat是追加指定的字符串,比如說可以給arr1追加4個字符

模擬實現(xiàn)及使用
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* sor, size_t num)
{
assert(dest && sor);
char* p = dest;
while (*p != '\0')
{
p++;
}
//此時已經(jīng)指向arr1中的\0
//把num個字符賦給*p
while (num--)
{
*p++ = *sor++;
}
return dest;
}
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world!!!!!";
size_t n = 0;
scanf("%d", &n);
my_strncat(arr1, arr2, n);
printf("%s", arr1);//n=5,hello world
return 0;
}
5.strstr的實現(xiàn)及模擬(字符串查找)
strstr是實現(xiàn)字符串查找的一個函數(shù),即在一個字符串中查找該字符串是不是含有另一個字符串

使用及模擬
#include<stdio.h>
#include<string.h>
#include<assert.h>
//char* strstr(const char*str1,const char*str2)
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
while (*p)
{
s1 = p;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)p;
p++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbpc";
//char* p = strstr(arr1, arr2);
char* p = my_strstr(arr1, arr2);
if (p == NULL)
printf("不存在");
else
printf("%s\n", p);//不包含,輸出結(jié)果為不存在
return 0;
}6.strtok函數(shù)(在字符串中定義用作分隔符的集合)

注意事項
1、strtok函數(shù)找到str中的下一個標(biāo)記,并將其用 \0 結(jié)尾,返回一個指向這個標(biāo)記的指針。(注:strtok函數(shù)會改變被其操作的字符串,所以在使用strtok函數(shù)切分的字符串一般都是臨時拷貝的內(nèi)容并且可修改。)
2、strtok函數(shù)的第一個參數(shù)不為 NULL ,函數(shù)將找到str中第一個標(biāo)記,strtok函數(shù)將保存它在字符串中的位置。
3、strtok函數(shù)的第一個參數(shù)為 NULL ,函數(shù)將在同一個字符串中被保存的位置開始,查找下一個標(biāo)記。
4、如果字符串中不存在更多的標(biāo)記,則返回 NULL 指針。
舉例使用
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "zinuo@qq.com.qdy";
char buf[200] = { 0 };
//p是用作分隔符的字符串首字符地址
const char* p = "@..";
//由于strtok函數(shù)會改變原字符串的內(nèi)容,所以一般都會拷貝一個用來使用
strcpy(buf, arr);
char* str = NULL;
for (str=strtok(buf,p); str != NULL; str=strtok(NULL,p) )
{
//用來做分隔符的字符都被改成了\0,下一次調(diào)用函數(shù)時,會從這個\0開始繼續(xù)往后查找分隔符,再次改為\0,一直到找完所有分隔符,返回NULL
printf("%s\n", str);//zinuo
//qq
//com
//qdy
}
return 0;
}
7.strerror函數(shù) (錯誤碼轉(zhuǎn)換錯誤信息)
#include<stdio.h>
#include<errno.h>//errno包含頭文件
#include<string.h>//strerror包含頭文件
int main()
{
//打開文件操作
FILE* pf = fopen("test.txt", "r");
//打開文件失敗,返回空指針,strerror可以將錯誤碼轉(zhuǎn)換成讓我們看得懂的錯誤信息
if (pf == NULL)
{
perror("lzn");//相當(dāng)于printf+strerror
//lzn: No such file or directory
//沒有這個文件,錯誤碼轉(zhuǎn)換為錯誤信息打印出來
printf("%s\n", strerror(errno));
//No such file or directory
return 1;
}
//關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
以上就是C語言中字符串庫函數(shù)的實現(xiàn)及模擬的詳細(xì)內(nèi)容,更多關(guān)于C語言字符串庫函數(shù)的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++學(xué)習(xí)筆記std::vector底層原理及擴容
這篇文章主要為大家介紹了C++學(xué)習(xí)之std::vector底層原理及擴容詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
關(guān)于數(shù)據(jù)結(jié)構(gòu)單向鏈表的各種操作
這篇文章主要介紹了關(guān)于數(shù)據(jù)結(jié)構(gòu)單向鏈表的各種操作,關(guān)于數(shù)據(jù)結(jié)構(gòu)鏈表的操作一般涉及的就是增刪改查,下面將關(guān)于無空頭鏈表展開介紹,需要的朋友可以參考下2023-04-04
采用C++實現(xiàn)區(qū)間圖著色問題(貪心算法)實例詳解
這篇文章主要介紹了采用C++實現(xiàn)區(qū)間圖著色問題(貪心算法),很經(jīng)典的算法問題,需要的朋友可以參考下2014-07-07
C++用winapi?socket實現(xiàn)局域網(wǎng)語音通話功能
這篇文章主要介紹了socket實現(xiàn)局域網(wǎng)語音通話?c++?winapi,功能介紹支持錄音設(shè)備查找以及播放設(shè)備查找,支持局域網(wǎng)語音通話,通話包含語音來電提醒和掛斷電話的提示信息,還能實時的獲取在線用戶的數(shù)量以及對應(yīng)的id,需要的的朋友一起看看2022-06-06

