C語(yǔ)言頭文件<string.h>函數(shù)詳解
1. strlen —— 求字符串長(zhǎng)度
1.1 strlen 的聲明與用處
strlen ,我們有一些英語(yǔ)基礎(chǔ)的話不難通過(guò)字面意思來(lái)知道這個(gè)函數(shù)是干嘛用的,str 表 string ,字符串的意思,len 表 length ,長(zhǎng)度的意思。也就是說(shuō),strlen 是求字符串長(zhǎng)度的函數(shù)。我們通過(guò) cplusplus 這個(gè)網(wǎng)站來(lái)觀察 strlen 的函數(shù)聲明以及各個(gè)參數(shù)的意義。

我們翻譯可以知道,strlen 所求的字符串長(zhǎng)度是字符串結(jié)束標(biāo)志之前的字符個(gè)數(shù)。即我們假設(shè)有字符串 "hello world" ,那么所求的字符串長(zhǎng)度就是 '\0' 之前的所有字符個(gè)數(shù),也就是 11 。那么這個(gè)字符串長(zhǎng)度是通過(guò)返回值返回的,所以我們要知道所求的字符串長(zhǎng)度是多少就必須定義一個(gè)變量來(lái)接收返回值。那么參數(shù)部分當(dāng)然就是字符串的首地址了。
1.2 strlen 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "hello world";
char* str2 = "hello world";
int len1 = strlen(str1);//數(shù)組名表首元素地址
int len2 = strlen(str2);//str2 指針變量存放的也是首元素地址
printf("%d\n", len1);
printf("%d\n", len2);
//這種寫(xiě)法也可以輸出長(zhǎng)度
//printf("%d\n", strlen(str1));
//printf("%d\n", strlen(str2));
return 0;
}
我們要注意的一點(diǎn)是,strlen 的返回值是一個(gè) size_t 類(lèi)型,即無(wú)符號(hào)整數(shù)。 它的意義在于求長(zhǎng)度時(shí)是不可能求出負(fù)數(shù)的,所以一定程度上優(yōu)化了內(nèi)存(使用有符號(hào)整形的話會(huì)浪費(fèi)掉用來(lái)存儲(chǔ)負(fù)數(shù)的空間)。
1.3 strlen 的模擬實(shí)現(xiàn)
我們上面已經(jīng)分析過(guò) strlen 的原理了,那么現(xiàn)在我們用自己所學(xué)過(guò)的只是來(lái)“創(chuàng)造”一個(gè)屬于自己的 strlen 函數(shù)。
#include <stdio.h>
#include <assert.h>
unsigned int my_strlen(const char* str)//我們不改變字符串的內(nèi)容,所以用 const 來(lái)進(jìn)行修飾
{
assert(str);//避免是一個(gè)空指針
unsigned int count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
int main()
{
char str1[] = "hello world";
char* str2 = "hello world";
int ret1 = my_strlen(str1);
int ret2 = my_strlen(str2);
printf("%d\n", ret1);
printf("%d\n", ret2);
return 0;
}2. strcpy —— 字符串拷貝
2.1 strcpy 的聲明與用處
我們對(duì)其字面翻譯進(jìn)行理解,str 表 string ,即字符串,cpy 表 copy ,即拷貝。也就是 strcpy 這個(gè)函數(shù)是用來(lái)進(jìn)行字符串拷貝的。那我們通過(guò) cplusplus 這個(gè)網(wǎng)站來(lái)觀察 strcpy 的聲明以及各個(gè)參數(shù)的意義。

我們翻譯過(guò)來(lái)就可以知道 strcpy 的功能,拷貝 source 指針指向的字符串至 destination 指針指向的數(shù)組當(dāng)中,拷貝的內(nèi)容包含字符串終止符。并且 destination 指針指向的數(shù)組必須有足夠大的空間容納拷貝之后的內(nèi)容。
由此我們知道, strcpy 需要兩個(gè)參數(shù),一個(gè)是數(shù)組,一個(gè)是字符串。并且數(shù)組的空間必須足夠大。返回值是返回?cái)?shù)組拷貝之前的地址。這么做的意義是防止拷貝之前的內(nèi)容丟失。
2.2 strcpy 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char dest[20] = "row your boat";
char src[] = "hello world";
strcpy(dest, src);
printf("%s\n", dest);
return 0;
}
這是 strcpy 最最常用的用法,我們只需要記住一點(diǎn)即可:拷貝過(guò)去的內(nèi)容是包含 '\0' 的。也就是說(shuō)即使我拷貝過(guò)去的字符串長(zhǎng)度沒(méi)有數(shù)組原來(lái)的字符串長(zhǎng)度長(zhǎng),但是我包含 '\0' 了,在 C 語(yǔ)言的角度來(lái)說(shuō) '\0' 之后的內(nèi)容就不算從頭往后看的字符串內(nèi)容了。

2.3 strcpy 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)//dest 指向的數(shù)組空間是要被改變的,但是 src 指向的字符串不需要改變
{
assert(dest && src);//防止其中某個(gè)是無(wú)效指針
char* ret = dest;
while (*dest++ = *src++)
; //注意 while 循環(huán)執(zhí)行了空語(yǔ)句
return ret;
}
int main()
{
char dest[30] = "gently down the stream";
char src[] = "life is but a dream";
my_strcpy(dest, src);
printf("%s\n", dest);
return 0;
}3. strcmp —— 字符串比較
3.1 strcmp 的聲明與用處
也是一樣,我們可以通過(guò)字面翻譯來(lái)大致了解這個(gè)函數(shù)是干嘛用的。str 表 string ,即字符串,cmp 表 compare ,即比較。我們同樣通過(guò) cplusplus 這個(gè)網(wǎng)站觀察這個(gè)函數(shù)的聲明以及各個(gè)參數(shù)的意義。

我們翻譯即可知道這個(gè)函數(shù)的原理。其原理就是:都是從兩個(gè)字符串的第一個(gè)字符開(kāi)始比較,如果這兩個(gè)字符相等,那么這兩個(gè)字符串都會(huì)進(jìn)行下一對(duì)字符比較,直到兩個(gè)字符不相等,然后進(jìn)行比較大小。如果第一個(gè)字符小于第二個(gè)字符,就會(huì)返回一個(gè)小于 0 的整數(shù),等于則返回 0 ,大于則返回一個(gè)大于 0 的整數(shù)。
其兩個(gè)參數(shù)都是要比較的字符串。為了方便理解,我們通過(guò)畫(huà)圖的形式來(lái)理解。



3.2 strcmp 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char* str1 = "abbbcd";
char* str2 = "abbbdd";
int ret = strcmp(str1, str2);
if (ret > 0)
printf("str1 > str2\n");
else if (ret < 0)
printf("str1 < str2\n");
else
printf("str1 == str2\n");
return 0;
}
3.3 strcmp 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
int my_strcmp(const char* str1, const char* str2)//兩個(gè)字符串的內(nèi)容都不需要修改,用 const 修飾
{
assert(str1 && str2);//防止是無(wú)效指針
while (*str1 == *str2)//如果相等則進(jìn)入循環(huán)
{
if (*str1 == '\0')//*str1 == '\0' 了并且進(jìn)入循環(huán)了,說(shuō)明兩個(gè)字符串比較完成了,沒(méi)有不相等的字符
return 0;
str1++;
str2++;
}
return *str1 - *str2;//兩個(gè)字符的差作為返回值
}
int main()
{
char* str1 = "abbbcd";
char* str2 = "abbbdd";
int ret = my_strcmp(str1, str2);
if (ret > 0)
printf("str1 > str2\n");
else if (ret < 0)
printf("str1 < str2\n");
else
printf("str1 == str2\n");
return 0;
}
4. strcat —— 字符串追加
4.1 strcat 的聲明與用處
我們通過(guò) cplusplus 這個(gè)網(wǎng)站來(lái)觀察 strcat 的聲明以及各個(gè)參數(shù)的意義。

翻譯一下即可直到 strcat 函數(shù)的用法:將 source 指針指向的字符串追加到 destination 指針指向數(shù)組并且有足夠大的空間(本人嘗試追加到字符串,但是失敗了),其追加的位置是 destination 指針指向的字符串的 '\0' 處,即從這個(gè)位置拷貝。需要注意的是,追加的 '\0' 的位置第一個(gè) '\0' 的位置。
4.2 strcat 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char str1[50] = "row row row your boat,";
char* str2 = "gently down the stream";
strcat(str1, str2);
printf("%s\n", str1);
return 0;
}
4.3 strcat 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* dest, const char* src)//src 指向的字符串是不改變內(nèi)容的,所以用 const 修飾
{
assert(dest && src);//確保兩個(gè)指針有效
char* ret = dest;
while (*dest)
dest++;//先找到 dest 指向的數(shù)組的第一個(gè) '\0' 的位置
while (*dest++ = *src++)//拷貝
;
return ret;
}
int main()
{
char str1[50] = "row row row your boat,";
char* str2 = "gently down the stream";
my_strcat(str1, str2);
printf("%s\n", str1);
return 0;
}
5. strncpy —— 長(zhǎng)度受限制的字符串拷貝
5.1 strncpy 的聲明與用處
strncpy 與 strcpy 的區(qū)別就是 strncpy 多了一個(gè)參數(shù)。這個(gè)參數(shù)是一個(gè)無(wú)符號(hào)的整數(shù),即可以自定義拷貝多少個(gè)字節(jié)的內(nèi)容。這就大大的方便了我們的使用,提高了 C 語(yǔ)言的靈活性。

5.2 strncpy 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20] = "row your boat";
char str2[] = "hello world";
strncpy(str1, str2, 3);//我們從 str2 中拷貝三個(gè)字節(jié)的內(nèi)容到 str1 去
printf("%s\n", str1);
return 0;
}

我們可以看到輸出的結(jié)果非常奇怪,這是因?yàn)楫?dāng)我們只拷貝三個(gè)字節(jié)的內(nèi)容時(shí),strncpy 是不會(huì)在后面補(bǔ) '\0' 的(即要多少內(nèi)容就拷多少內(nèi)容),這就導(dǎo)致了我們能夠看到 str1 數(shù)組里面拷貝之前的內(nèi)容。
5.3 strncpy 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strncpy(char* dest, const char* src, unsigned int num)
{
assert(dest && src);//確保兩個(gè)指針有效
char* ret = dest;
while (num--)//拷貝幾個(gè)字節(jié)
{
*dest = *src;
dest++;
src++;
}
return ret;
}
int main()
{
char str1[20] = "row your boat";
char str2[] = "hello world";
my_strncpy(str1, str2, 3);
printf("%s\n", str1);
return 0;
}
6. strncmp —— 長(zhǎng)度受限制的字符串比較
6.1 strncmp 的聲明與用處
strncmp 與 strcmp 的功能是一模一樣的,原理也就是一模一樣的。也就是說(shuō)掌握了 strcmp 就能夠掌握 strncmp 。strncmp 只是相較于 strcmp 多了一個(gè)參數(shù),這個(gè)參數(shù)是一個(gè)無(wú)符號(hào)整數(shù),代表的是字節(jié)。即我們想要比對(duì)多少字節(jié)。我們通過(guò) cplusplus 這個(gè)網(wǎng)站可以觀察這個(gè)函數(shù)的聲明以及各個(gè)參數(shù)的意義。

6.2 strncmp 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char* str1 = "abbbcd";
char* str2 = "abbbdd";
int ret=strncmp(str1, str2,3);//我們只想比較字符串的前三個(gè)字節(jié)
if (ret > 0)
printf("str1 > str2\n");
else if (ret < 0)
printf("str1 < str2\n");
else
printf("str1 == str2\n");
return 0;
}
6.3 strncmp 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
int my_strncmp(const char* str1, const char* str2, unsigned int num)//兩個(gè)字符串的內(nèi)容都不需要變,所以用 const 修飾
{
assert(str1 && str2);
while (num-- && *str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char* str1 = "abbbcd";
char* str2 = "abbbdd";
int ret = my_strncmp(str1, str2, 3);//我們只想比較字符串的前三個(gè)字節(jié)
if (ret > 0)
printf("str1 > str2\n");
else if (ret < 0)
printf("str1 < str2\n");
else
printf("str1 == str2\n");
return 0;
}
7. strncat —— 長(zhǎng)度受限制的字符串追加
7.1 strncat 的聲明與用處
同理,掌握了 strcat 就能掌握 strncat 。strncat 其參數(shù)多了一個(gè)無(wú)符號(hào)整形的參數(shù),其意義代表字節(jié)數(shù)。即我們可以自定義想要追加多少個(gè)字符至另一個(gè)字符串的后面。我們可以通過(guò) cplusplus 這個(gè)網(wǎng)站觀察 strncat 的聲明以及各個(gè)參數(shù)的意義。

7.2 strncat 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char str1[50] = "row row row your boat,";
char str2[] = "gently down the stream";
strncat(str1, str2, 6);//我們只想追加 6 個(gè)字節(jié)的字符到 str1 中
printf("%s\n", str1);
return 0;
}
在這里如果我們注意觀察的話,就會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題。我們追加過(guò)去的 6 個(gè)字節(jié)的字符并不包含 '\0' ,但是在最后輸出打印的時(shí)候好像在字符串尾又被賦予了 '\0' 。那么這就不得不提及 strncat 的特性,即 strncat 會(huì)在要追加的字符串后面補(bǔ) '\0' 。

7.3 strncat 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strncat(char* dest, const char* src, unsigned int num)//str2 中的字符串不需要被修改,所以用 const 修飾
{
assert(dest && src);//確保兩個(gè)指針是有效指針
char* ret = dest;//記錄返回值
while (*dest)//先找到 dest 指向的 '\0' 的位置
dest++;
while (num-- && (*dest++ = *src++) )//拷貝限制的字節(jié)數(shù)
;
*dest = '\0';
return ret;
}
int main()
{
char str1[50] = "row row row your boat,";
char str2[] = "gently down the stream";
my_strncat(str1, str2, 8);
printf("%s\n", str1);
return 0;
}
小結(jié)
我們上面介紹了許多長(zhǎng)度不受限制的字符串函數(shù)和長(zhǎng)度受限制的字符串函數(shù)。那么受限制和不受限制有什么區(qū)別呢? 首先不受限制的字符串函數(shù)的靈活性是比較低的,因?yàn)橹荒懿僮髡麄€(gè)字符串。但是受限制的字符串函數(shù)的靈活性是比較高的,可以自定義操作的字符個(gè)數(shù)。并且,長(zhǎng)度受限制的字符串函數(shù)相對(duì)于長(zhǎng)度不受限制的字符串函數(shù)來(lái)說(shuō)是比較安全的。注意是受限制的相對(duì)于不受限制的比較安全。
8. strstr —— 字符串查找
8.1 strstr 的聲明與用處
strstr 通過(guò)字面翻譯過(guò)來(lái)就是兩個(gè)字符串。那么其意義是在其中一個(gè)字符串里面查找另外一個(gè)字符串。我們可以通過(guò) cplusplus 這個(gè)網(wǎng)站來(lái)觀察 strstr 的聲明以及各個(gè)參數(shù)的意義。

我們翻譯一下即可知道 strstr 的某些原理。如果在字符串 1 里面查找到了字符串 2 ,那么就返回字符串 2 出現(xiàn)在字符串 1 中的首地址。如果沒(méi)有找到字符串,就返回一個(gè)空指針。
8.2 strstr 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char* str1 = "row row row your boat,gently down the stream";
char* str2 = "row your boat";
char* ret = strstr(str1, str2);//在 str1 中查找 str2
printf("%s\n", ret);
return 0;
}
可以看到返回值是返回 str2 第一次出現(xiàn)在 str1 中的首地址。
8.3 strstr 的模擬實(shí)現(xiàn)
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)//不需要改變其內(nèi)容,用 const 修飾
{
assert(str1 && str2);//避免是無(wú)效指針
const char* s1 = str1;
const char* s2 = str2;
const char* cp = str1;//這個(gè)指針變量是至關(guān)重要的
while (*cp)
{
s1 = cp;
s2 = str2;
//在 str1 中查找 str2 的核心循環(huán)
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')//查找完成
return (char*)cp;
cp++;
}
return NULL;
}
int main()
{
char* str1 = "row row row your boat,gently down the stream";
char* str2 = "row your boat";
char* ret = my_strstr(str1, str2);
printf("%s\n", ret);
return 0;
}
我們來(lái)通過(guò)畫(huà)圖來(lái)詳解一下思路。




9. strtok —— 字符串切割
9.1 strtok 的聲明與用處
對(duì)于這個(gè)函數(shù),我們只要了解了基本的使用方法即可。我們通過(guò) cplusplus 這個(gè)網(wǎng)站來(lái)觀察 strtok 的聲明以及各個(gè)參數(shù)的意義。

這段英文的篇幅太長(zhǎng)了,我來(lái)解釋一下核心部分:我們提供兩個(gè)參數(shù)給 strtok ,一個(gè)是字符串,一個(gè)是要切割的標(biāo)記。如果在這個(gè)字符串當(dāng)中出現(xiàn)了這個(gè)標(biāo)記,那么這個(gè)位置將被修改為 '\0' ,并且返回這個(gè)標(biāo)記之前的字符串地址。如果要進(jìn)行二次傳參,那么只需要傳一個(gè)空指針即可。
9.2 strtok 的用法
#include <stdio.h>
#include <string.h>
int main()
{
char* str1 = "row@row~row%your^boat,gently@down~the^stream";
char* str2 = "@~%^";
//將 str1 拷貝至 tmp 數(shù)組,這樣不會(huì)丟失 str1 的原始數(shù)據(jù)
char tmp[50] = { 0 };
strcpy(tmp, str1);
char* ret = NULL;
for (ret = strtok(tmp, str2); ret != NULL; ret = strtok(NULL, str2))
{
printf("%s ", ret);
}
return 0;
}
10. strerror —— 錯(cuò)誤碼解析
10.1 strerror 的聲明與用處
我們需要普及的一個(gè)點(diǎn)是,在 C 語(yǔ)言中,程序發(fā)生錯(cuò)誤的時(shí)候,是有一個(gè)隱藏的全局變量 errno 的,這個(gè)變量是一個(gè)整數(shù)的,譬如 0 ,1,2,3,....等都代表不同的錯(cuò)誤信息,而 strerror 的作用就是翻譯這個(gè)錯(cuò)誤碼。我們可以通過(guò) cplusplus 這個(gè)網(wǎng)站來(lái)觀察 strerror 的聲明以及各個(gè)參數(shù)的意義。

10.2 strerror 的用法
#include <stdio.h>
#include <string.h>
int main()
{
FILE* p;
p = fopen("test.txt", "r");//在我們的工程目錄下并沒(méi)有 test.txt 這個(gè)文件
if (p == NULL)//那么打不開(kāi) p 就是一個(gè)空指針
{
printf("%s\n", strerror(errno));//這里就會(huì)解釋為什么是空指針的原因
}
return 0;
}
到此這篇關(guān)于C語(yǔ)言頭文件<string.h>函數(shù)詳解的文章就介紹到這了,更多相關(guān)C語(yǔ)言頭文件<string.h>函數(shù)詳解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c語(yǔ)言中g(shù)etch,getche,getchar的區(qū)別
getche() 和getch()很相似,它也需要引入頭文件conio.h,那它們之間的區(qū)別又在哪里呢?不同之處就在于getch()無(wú)返回顯示,getche()有返回顯示2013-09-09
VC實(shí)現(xiàn)ODBC數(shù)據(jù)庫(kù)操作實(shí)例解析
這篇文章主要介紹了VC實(shí)現(xiàn)ODBC數(shù)據(jù)庫(kù)操作的方法,非常有實(shí)用價(jià)值,需要的朋友可以參考下2014-07-07
Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)生成器
有兩種應(yīng)用場(chǎng)景需要用到數(shù)據(jù)生成器,一種是需要測(cè)試數(shù)據(jù)庫(kù)性能,一種是隨機(jī)模擬生成一堆數(shù)據(jù),用來(lái)測(cè)試程序的性能。本文將利用Qt實(shí)現(xiàn)通用數(shù)據(jù)生成器,需要的可以參考一下2022-02-02
C語(yǔ)言輸出孿生素?cái)?shù)的實(shí)現(xiàn)示例
本文主要介紹了C語(yǔ)言輸出孿生素?cái)?shù)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01
Qt掃盲篇之QRegExp正則匹配類(lèi)總結(jié)
這篇文章主要給大家介紹了關(guān)于Qt掃盲篇之QRegExp正則匹配類(lèi)總結(jié)的相關(guān)資料,QRegExp是Qt框架中的一個(gè)類(lèi),用于進(jìn)行正則表達(dá)式的匹配和處理,它提供了多種模式來(lái)匹配不同的字符串,需要的朋友可以參考下2023-12-12

