柚子快報邀請碼778899分享:C:字符串函數(shù)(續(xù))-學(xué)習(xí)筆記
柚子快報邀請碼778899分享:C:字符串函數(shù)(續(xù))-學(xué)習(xí)筆記
穗
一些閑話:
最近玩了這款餓殍-明末千里行,不知大家是否有聽過這款游戲,頗有感觸?。?!
游戲中最讓我難以忘懷的便是餓殍穗線的故事,生在如今時代的我之前無法理解杜甫在目睹人間悲劇時的心情,但現(xiàn)在我似乎有些能夠共情了。在游戲中我以第三人稱視角目睹了一個美好家庭的支離破碎的過程,那種痛苦難以言表。天災(zāi)人禍,餓殍遍野,有人在笑,有人在哭,富人更富,窮人死亡。
目錄
一些閑話:
?
前言:
1、?strcpy與strncpy
1.1??strcpy的使用和模擬
1.1.1??strcpy的使用
?1.1.2??strcpy的模擬實現(xiàn)
1.2 strncpy的使用?
2、strcat與strncat
2.1?strcat的使用與模擬
2.1.1?strcat的使用
2.1.2 strcat的模擬實現(xiàn)
2.2 strncat的使用?
?編輯
3、strcmp與strncmp
3.1 strcmp的使用與模擬
3.1.1 strcmp的使用
3.1.1 strcmp的模擬實現(xiàn)
3.2 strncmp的使用?
結(jié)語:
?
前言:
本篇文章將延續(xù)上一篇繼續(xù)介紹字符串函數(shù),希望能夠?qū)Υ蠹矣兴鶐椭?/p>
話不多說,直接上正文
上一篇文章我們將字符串函數(shù)分為四類,并介紹了strlen函數(shù)
本篇文章小編將會帶著大家了解后面三類字符串函數(shù)
1、?strcpy與strncpy
1.1??strcpy的使用和模擬
1.1.1??strcpy的使用
strcpy -- string copy? ?字符串拷貝
這是什么意思呢?
char ch1[] = "Hello,world";
char ch2[20];
比如說你有一個字符串ch1,想要將ch1中的內(nèi)容拷貝到ch2中,這時候我們就可以使用strcpy函數(shù)了
那么這個函數(shù)該怎么使用呢?
函數(shù)原型:
char * strcpy ( char * destination, const char * source );
我們來看一下cplusplus上是怎么說明的
?也就是說destination是目標(biāo)空間,sourse是源頭
我們將源頭里的內(nèi)容拷貝到目的地中,在結(jié)合我們上面舉的例子,我們想將ch1中的內(nèi)容拷貝到ch2中,那么ch1便是源頭,ch2便是目標(biāo)空間。
代碼實現(xiàn):
#include
#include
int main()
{
char ch1[] = "Hello,world";
char ch2[20];
strcpy(ch2, ch1);
printf("%s\n", ch2);
return 0;
}
?結(jié)果展示:
這便是strcpy的作用,當(dāng)我們學(xué)會了strcpy的使用,我們還需要知道為什么,知其然知其所以然
我們驗證一下有沒有將\0一同拷貝
char ch1[] = "Hello";
char ch2[20] = "*************";//為了方便觀察是否拷貝了\0
strcpy(ch2, ch1);
從調(diào)試過程中我們可以發(fā)現(xiàn) \0 的確是拷貝過來了。?
既然strcpy會將源頭內(nèi)容中的\0拷貝過來,那么如果源頭不包含\0的話,會有什么結(jié)果呢?
char ch1[] = { 'a','b','c'};
char ch2[20] = "*************";//為了方便觀察是否拷貝了\0
strcpy(ch2, ch1);
?
這里為什么會出現(xiàn)這樣的錯誤呢?
就是因為源頭內(nèi)容中不存在\0。沒有\(zhòng)0
strcpy拷貝就停不下來,會一直拷貝,直到越界報錯。
因此?strcpy函數(shù)的使用需要注意幾點
源字符串必須以 '\0' 結(jié)束。目標(biāo)空間必須足夠大,以確保能存放源字符串目標(biāo)空間必須可修改
?1.1.2??strcpy的模擬實現(xiàn)
當(dāng)學(xué)會strcpy怎么使用后,我們也可以嘗試自己寫一個函數(shù)來模擬一下strcpy
#include
#include
void my_strcpy(char* ch2, char* ch1)
{
while (*ch1 != '\0')
{
*ch2 = *ch1;
*ch2++;
*ch1++;
}
*ch2 = *ch1;//如果*ch1 = '\0',ch2 = '\0'
}
int main()
{
char ch1[] = "hello";
char ch2[20];
my_strcpy(ch2, ch1);
printf("%s\n", ch2);
return 0;
}
當(dāng)ch1不等于 '\0' 的時候,就繼續(xù)向后尋找,且令ch2 = ch1;
當(dāng)ch1等于 '\0' 的時候,則不再向后尋找,令ch2 = ch1;
void my_strcpy(char* ch2, char* ch1)
{
while (*ch1 != '\0')
{
*ch2 = *ch1;
*ch2++;
*ch1++;
}
*ch2 = *ch1;//如果*ch1 = '\0',ch2 = '\0'
}
上面那個模擬實現(xiàn)還可以進(jìn)行一些優(yōu)化,我們可以再進(jìn)行簡化一下
?比如說*ch2++和*ch1++可以與上面的合并一下
*ch2++ = *ch1++;
后置++是用完之后再++,所以和前面的表示是一樣的。
?前面我們將*ch1 分為是否等于 '\0',這里也可以合并一下
void my_strcpy(char* ch2, char* ch1)
{
while (*ch2++ = *ch1++ )
{
;
}
}
分析一下:?
?循環(huán)結(jié)束是因為\0 的ASCLL值為0,0為假,循環(huán)終止。
這樣寫的好處是既可以賦值,賦完的值還可以用來判斷。
還有一個問題,我們使用strcpy函數(shù)主要是為了將源頭內(nèi)容拷貝到目標(biāo)空間中,因此,我們不希望源頭被改動,因此,可以使用const修飾一下源頭
void my_strcpy(char* ch2, const char* ch1)
這樣的話我們就不能夠在my_strcpy函數(shù)中修改ch1中的內(nèi)容了,?使得程序更加穩(wěn)定。
關(guān)于指針我們最擔(dān)心的是什么?我們會擔(dān)心它是不是空指針,因此可以在解引用之前使用assert斷言一下。
assert(ch2 && ch1 );//只要有一個是空指針就會報錯
注意,assert使用需要添加頭文件
最終版本:
#include
#include
#include
void my_strcpy(char* ch2, const char* ch1)
{
assert(ch2 && ch1 );//只要有一個是空指針就會報錯
while (*ch2++ = *ch1++ )
{
;
}
}
int main()
{
char ch1[] = "hello";
char ch2[20];
char* ret = my_strcpy(ch2,ch1);
printf("%s\n", ret);
return 0;
}
1.2 strncpy的使用?
這個函數(shù)和strcpy是不是很相似,它們不僅名字相似,用法也及其相似
他們之間就相差了一個變量,strncpy比strcpy多了一個變量num,那么num這個變量的作用是什么呢?
? num的作用
其實它們之間唯一的區(qū)別就是strncpy是長度受限制的字符串函數(shù),而strcpy是長度不受限制的字符串函數(shù),也就是說你源頭字符串長度不論多少,都會全部給你?拷貝到目標(biāo)空間中;而strncpy則會通過num的值來拷貝源頭字符串長度到目標(biāo)空間。
//我們要拷貝arr1中的前五個元素
char arr1[] = "hello world";
char arr2[30] = { 0 };
strncpy(arr2,arr1,5);
printf("%s ", arr2);
最終打印出來的便是我們想要的前五個字符。
有沒有覺得strncpy函數(shù)比strcpy函數(shù)要靈活一些,使用strncpy函數(shù)我們可以根據(jù)自己的需求來決定拷貝多少字符,但是使用strcpy函數(shù)卻只能拷貝全部的字符。
strncpy加上了一個長度的限制使得拷貝變的更加靈活。
char arr1[] = "he";
char arr2[30] = "xxxxxxxxx";
strncpy(arr2,arr1,5);
printf("%s ", arr2);
如果我們源頭字符串不足所要拷貝的長度,會怎樣呢?
從上圖中我們可以看到,如果不滿足條件,后面會自動補充上\0。
2、strcat與strncat
2.1?strcat的使用與模擬
2.1.1?strcat的使用
strcat的作用是實現(xiàn)字符串的鏈接?
那么什么是字符串的鏈接呢?
比如說有一個字符數(shù)組arr,內(nèi)容是"hello",想要在后面追加world,這時候就需要使用strcat函數(shù)了
char arr[20] = "hello ";
strcat(arr, "world");
這樣我們就可以將world鏈接到arr中,打印arr,可以看到此時arr的內(nèi)容變成了 "hello world"
函數(shù)原型:
char * strcat ( char * destination, const char * source );
cplusplus中對strcat的解釋:
這里有兩個問題,第一個問題是strcat函數(shù)的追加是不是從我們字符串遇到的第一個\0開始追加?
第二個問題是 上圖中的 '\0'?是原來的函數(shù)把 "world" 字符串中的' \0 '追加到arr中的嗎?
我們來驗證一下
char arr[20] = "hello\0xxxxxxx ";
strcat(arr, "world")
?
上圖就可以解決我們的兩個問題了,strcat函數(shù)的追加是從我們字符串遇到的第一個\0開始追加
"world" 字符串中的' \0 '也會追加到arr中
因此,我們可以整理一下strcat函數(shù)的追加方式:
1.找到目標(biāo)空間中的第一個'\0';
2.然后從\0的位置開始追加源頭字符串;
3.源頭字符串的內(nèi)容包括\0都會追加到目標(biāo)空間。
2.1.2 strcat的模擬實現(xiàn)
學(xué)會了strcat函數(shù)的使用,接下來我們嘗試模擬一下;
//dest指目標(biāo)空間也就是arr;src指源頭,也就是所要追加的字符串首字符的地址
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1.找目標(biāo)空間中的\0
while (*dest != '\0')
dest++;
//2.拷貝數(shù)據(jù)
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr[20] = "hello ";
my_strcat(arr, "world");
printf("%s ", arr);
return 0;
}
提出一個問題,我們能不能用上面自己模擬的my_strcat來實現(xiàn)自己給自己追加的操作??
因此,使用上面自己定義的函數(shù)來實現(xiàn)自己給自己追加最終會出現(xiàn)死循環(huán)問題。?
如果我們使用庫里面的strcat函數(shù)呢?
當(dāng)前程序可以,但是呢,沒法保證所有程序都可以成功運行,一般我們不會使用這個函數(shù)給自己追加。?一般自己自己追加都使用 strncat 函數(shù)
2.2 strncat的使用?
strncat函數(shù)與strcat函數(shù)的用法也是一樣的,都是實現(xiàn)字符串的鏈接,不過前者會加上鏈接字符的長度限制。
strncpy用法展示:?
char arr[30] = "hello ";
strncat(arr,"liangjing",5 );
printf("%s ", arr);
如果我們要追加的字符串少于所規(guī)定的長度呢?
char arr[30] = "hello\0xxxxxx ";
strncat(arr,"lj",5);
printf("%s ", arr);
我們可以發(fā)現(xiàn)strncat函數(shù)不會和strncpy函數(shù)一樣,不滿足會給你補\0,?strncat函數(shù)只會把最多追加到目標(biāo)空間。
3、strcmp與strncmp
3.1 strcmp的使用與模擬
3.1.1 strcmp的使用
strcmp -- string compare -字符串的比較
?strcmp函數(shù)的作用是比較兩個字符串的大小
對應(yīng)位置上的字符進(jìn)行比較,按照ASCII值的大小,注意比較的不是字符串的長度。
比如說:
?函數(shù)原型:
int strcmp ( const char * str1, const char * str2 );
我們來看一看這個函數(shù)的參數(shù)
const char * str1是一個字符指針,const char * str2 也是一個字符指針,該函數(shù)將兩個指針指向的字符串進(jìn)行比較,比較后,在通過返回值來告訴我們誰大誰小
這是什么意思呢?如果說str1指向的字符串比str2指向的字符串大,則返回一個大于0的數(shù)字,如果相等,返回0,如果str1指向的字符串比str2指向的字符串小,則返回一個小于0的數(shù)字。
char arr1[ ] = "abcdef ";
char arr2[ ] = "abc";
int ret = strcmp(arr1, arr2);
printf("%d",ret);
我們來看一下返回值大?。?/p>
返回1,也就是說明字符串a(chǎn)rr1大于字符串2
我們也可以將這個代碼換一種表示,或許會更加直觀
int main()
{
char arr1[ ] = "abcdef ";
char arr2[ ] = "abc";
int ret = strcmp(arr1, arr2);
if (ret > 0)
printf(">\n");
else if (ret < 0)
printf("<\n");
else
printf("=\0");
return 0;
}
這樣使用比較符號可以更加直觀。
注意:strcmp函數(shù)是通過比較兩個字符串對應(yīng)位置ASCII值的大小來判斷兩個字符串的大小,而不是通過字符串長度。?
3.1.1 strcmp的模擬實現(xiàn)
學(xué)會了使用strcmp,我們可以嘗試自己來模擬實現(xiàn)該函數(shù)
int my_strcmp(const char* str1, const char* str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[ ] = "abcdef ";
char arr2[ ] = "abc";
int ret = my_strcmp(arr1, arr2);
if (ret > 0)
printf(">\n");
else if (ret < 0)
printf("<\n");
else
printf("=\0");
return 0;
}
3.2 strncmp的使用?
與上類似,直接展示用法:
#include
#include
#include
int main()
{
char arr1[30] = "abcdef ";
char arr2[30] = "abcmne";
int ret = strcmp(arr1,arr2,3);
if (ret > 0)
printf(">\n");
else if (ret < 0)
printf("<\n");
else
printf("=\0");
return 0;
}
?這里的3是指只比較字符串a(chǎn)rr1,arr2中前三個字符
結(jié)語:
本篇文章主要是介紹了strcpy,strcat,strcmp以及與它們極其相似的strncpy,strncat,strncmp函數(shù),下篇文章將會結(jié)束字符串函數(shù)模塊。
?
?
柚子快報邀請碼778899分享:C:字符串函數(shù)(續(xù))-學(xué)習(xí)筆記
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。