认识strstr
strstr的功能是在一个字符串中检测它是否包含另一个字符串,如果包含,返回该包含的字符串首元素地址,若不包含,则返回空指针,它的参数为两个数组指针。使用举例:
int main()
{
char* str1 = "abcdefg";
char* str2 = "def";
printf("%s\n", strstr(str1, str2));
return 0;
}
直观上看,strstr第一个参数似乎是较长的字符串的地址,第二个参数似乎是较短的字符串的地址。如果我们将较短的字符串叫做key字符串,较长的字符串叫做库字符串,那这个函数是在库字符串里寻找key字符串,如果找到了,那么他们之间就是包含和被包含的关系,第一个参数指向的字符串的长度要大于等于第二个。
在这段代码中,字符串str2被检测到在字符串str1中,strstr返回了str2的首元素地址。在打印的过程中,printf函数将这个地址看成了从str2首字符到str1的最后一个字符之间所有字符构成的字符串,打印结果是“defg”。
下面进入重头戏
模拟实现strstr
下面是字符串查找的基本实现方法,也是库函数strstr中给的实现方法
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2 = NULL;
const char* cp = str1;
if (*str2 == '\0')
{
return (char*)str1;
}
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
这段代码解决问题的思路也许能给我们带来许多启发。
首先我们的总体思路是先在字符串str1中寻找我们所要查找的字符串str2的首元素,如果找到了,那就比对他们各自后面的第二个元素,若第二个元素也相同且不为’\0’,则继续比较第三个元素,一直比对到比较的元素中出现’\0’,此时跳出循环,判断此’\0’是不是属于str2,如果属于,那么符合要求,我们直接返回此时找到的首元素地址,如果’\0’属于str1,不符合要求,我们接着开头继续在str1中查找str2首元素。如果当首元素查到str1的最后一个字符后还是没有查到,则我们返回空指针。具体实现的过程中,我们引入了几个中间变量——s1、s2和cp,其中s1和s2主要用于在循环过程中同步解引用来比对两字符串相应位置字符是否相同,cp预示着查找首元素的进度,每进入一次循环都代表着有str1中有一个字符被拿来和str2[0]比较一次。
在具体实现过程中,我们首先创建三个字符类型的指针,并给cp赋上str1的值,接着判断str2是否为‘\0’,若是,则我们直接返回str1的地址(因为此时意味着str2内没有有效元素,我们直接返回str1的值)。排除了这种情况之后,我们直接进入主循环,主循环条件是cp,并且每一次循环过后cp++,我们注意到在cp后移到指向到’\0’的位置之前循环条件一直为真,每一个元素被cp指向时都会进入一次循环,判断它是否为str2[0],进而向后查找一次字符串。进入循环后我们令s1=cp,s2=str2并且利用下面的循环来进行查找,之后就按照我们的思路一步一步来实现即可。
这个代码说实话解说起来是很有难度的,我现在的水平只能勉强做到将其看懂,可我现在是无论如何都写不出这样的代码的,先把问题留在这里,等我以后水平足够了再来进行深度解说。