C語言中的字符串函數有如下這些
- 獲取字符串長度
- strlen
- 長度不受限制的字符串函數
- strcpy
- strcat
- strcmp
- 長度受限制的字符串函數
- strncpy
- strncat
- strncmp
- 字符串查找
- strstr
- strtok
- 錯誤信息報告
- strerror
字符串查找
strstr
還是一樣,先看看如何使用它,對吧哈哈哈。
int main()
{
char* p1 = "abcdef";
char* p2 = "def";
// 在abcdef中找找def,找到的話返回它的地址,找不到返回空指針
char* rest = strstr(p1, p2);
if (rest == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", rest);
}
return 0;
}
老規矩,我們還是看看文檔是怎樣說的,如下
char * strstr ( const char * str1, const char * str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
返回一個指針,它指向str2,該str2是在str1中第一次出現的str2,或者一個空指針,如果str2不是str1的子串。
The matching process does not include the terminating null-characters, but it stops there.
這個匹配過程不包含'\0',但是它會停在那里。
實現
我們需要想想,它是如何實現字符串查找的?
有兩個字符串,str1和str2,在str1中查找str2,那么我們需要兩個指針p1
和p2
來進行,p1
指向str1開頭,p2
指向str2開頭,然后獲取字符一一比較。
如果*p2
為'\0'
那么說明str2是空字符串,不能進行比較,就返回p1
,即返回str1的地址。
如果*p2
不為'\0'
,就說明不是空字符串,同時,也要判斷*p1
是否為空字符串,不是就可以進行查找。
查找的話,此時,我就通過*p1 == *p2
判斷*p1
等於*p2
?等於就都進行偏移,即p1++
和p2++
,然后繼續判斷,這里就成了一個循環,一直循環,直到它們兩個不相等跳出循環。跳出循環后,如果*p2
等於'\0'
,說明已經查找到了,直接返回p2就好。如果*p2
不等於'\0'
,那么就p1就進行偏移,往后移動,繼續判斷,這里也形成了一個循環。到這里,基本的邏輯就這樣了。
下面看看代碼的實現。
斷言指針不為空是個好習慣~
char* my_strstr(const char* p1, const char* p2)
{
// 保證指針的有效性,所以assert
assert(p1 != NULL);
assert(p2 != NULL);
// 如果p2是空字符串,那就比不了
if (*p2 == '\0')
{
printf("空字符串比不了,返回p1");
return p1;
}
// 真正的查找實現
while (*p1) // 判斷*p1是'\0'嗎?不是就可以查找
{
//while (*p1 == *p2) // 判斷*p1等於*p2?等於就都進行偏移
while ((*p1 != '\0') && (*p2 != '\0') && (*p1 == *p2) ) // 繼續完善,*p1,*p2都不能是\0,遇到\0就結束了,沒東西可比了
{
p1++;
p2++;
}
if (*p2 == '\0')
{
// 說明匹配到了
return p2;
}
p1++; // 不等於,那么p1往后偏移
}
}
是的,到這里還沒有結束,上面看似可以進行匹配了,但是代碼還是有問題,比如遇到這種情況的時候
int mian()
{
char* p1 = "abbbcdef";
char* p2 = "bbc";
char* rest = my_strstr(p1, p2);
return 0;
}
第一個字符串的第一個字符a與第二個字符串的第一個字符b進行比較,發現不相等,那么p1就進行偏移,p1往后移動
此時b與b相比,相等,那么p1和p2都進行偏移,都往后移動
還是b與b相比,相等,繼續偏移
此時b與c相比,不相等,那么p1進行偏移,此時p1指向的就是第五個字符c了,后面繼續比較下去,肯定都不相等,也就是說找不到bbc,但是第一個字符串里明明有bbc,就是找不到,這就是會出現的問題。
那如何解決這個問題?
我們知道,如果可以讓p1重新回去第二個字符的位置開始比較,那么肯定就能夠找到bbc,但是上面的代碼中,使p1發生改變了,p1不知道第二個字符b的位置,直接從第五個字符c的位置開始了。
所以,要解決的話,我們就需要一個變量記錄從哪個位置開始匹配的,然后我們不要去改動p1,同時保險起見,也不要改動p2,那么我們就可以搞多兩個指針變量s1
和s2
,作為p1
和p2
的拷貝,對這兩個變量進行操作,就OK了~然后搞多一個變量current
,作為當前需要移動的指針。
char* my_strstr(const char* p1, const char* p2)
{
// 保證指針的有效性,所以assert
assert(p1 != NULL);
assert(p2 != NULL);
// p1,p2不要往后動
// 需要一個變量記錄從哪個位置開始匹配
//char* s1 = p1; // 這里賦值無所謂,就給NULL好了
char* s1 = NULL;
char* s2 = NULL;
char* current = (char*)p1; // 這里強制類型轉換,因為p1是const修飾,賦值給了char*這個沒有保護的,所以強轉下,不然會報警告
// 如果p2是空字符串,那就比不了
if (*p2 == '\0')
{
printf("空字符串比不了,返回p1");
return (char*)p1;
}
// 真正的查找實現
while (*current) // 判斷*current是'\0'嗎?不是就可以查找
{
s1 = current;
s2 = (char*)p2;
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
// 說明匹配到了
return current; // 返回子串地址
}
if (*s1 == '\0')
{
// 如果子串比較長,那么肯定是找不到的
return NULL;
}
current++; // 不等於,那么current往后偏移
}
return NULL; //找不到子串
}
最后,謝謝你看到這里,謝謝你認真對待我的努力,希望這篇博客有幫到你
你輕輕一個贊,就是我世界里的一顆星
還有因本人水平有限,如有錯誤以及不足之處,歡迎靚仔靚女們
指出。