Recurrence and variations of strstr function (calculating the number of substrings)

1.Introduction to strstr

#include<string.h>
char* strstr(const char* str1,const char* str2);

Input the array name of the parent string and the array name of the substring. The function will return a pointer of type char*. This pointer points to the address of the first element of the first substring in the parent string.

So how do we achieve it?

2. Implement strstr

First let’s look at an error demonstration.

We let the first elements of str1 and str2 keep comparing until *str1==*str2, and let it loop to compare each element. If the elements before ‘\0’ are equal, then return a str1-n, and the mother character The address of the first element of the substring in the string. If they are not equal, a null pointer is returned. But think about it, is this right? What if we encounter a string that contains aaas? When we want to find as, str2 can no longer return to the first element. We want str2 to automatically return to the first element when it recognizes a for the first and second time. element, this requires a loop to reinitialize str2 every time it is compared so that it points to the first element. Since str2 returns to the first element, does str1 need to return to the position of the second a? Maybe there is nothing when there are two elements. Impact, but what if the substring has three or four elements? After the first comparison, it moves back three elements, and may even skip the substring directly. If we define another variable num To record the number of elements that it has walked backwards when it encounters a, you have to add an if statement to subtract num-1 and return to the position of the second a. This is too troublesome.

char* my_strstr(const char*str1,const char* str2)
{
    int n=0;
    if(*str1!=*str2)
    {
        str1 + + ;
    }
    else
    {
        while(*str1=*str2)
        {
            n + + ;
            str1 + + ;
            str2++;
        }
    }
    if(*str2=='\0')
        return str1-n;
    else
        return NULL;
}

Define a p pointer improvement program

Use p to record the starting position, and then compare str1 + + and str2 + + one by one. If they are equal, return the pointer p and the address of the first element. If they are not equal, reinitialize str2, and then make str1 equal to p after p + +

Here, we’d better keep str1 and str2 fixed and not change them, and assign them to s1 and s2.

#include<assert.h>
char* my_strstr(const char* str1, const char* str2,int *n)
{
    //Make sure it is not a null pointer
    assert(str1 & amp; & amp; str2);
    const char* s1 = str1;
    const char* s2 = str2;
    const char* p = str1;
    //Initialize three pointer variables
}

Then we need to use a while loop to initialize it after each comparison.

#include<assert.h>
char* my_strstr(const char* str1, const char* str2,int *n)
{
    assert(str1 & amp; & amp; str2);
    const char* s1 = str1;
    const char* s2 = str2;
    const char* p = str1;
    //Take *p as the condition. If *p=='\0', it means there are no identical elements, and a null pointer will be returned at the end of the loop.
    while (*p)
    {
        //Requires initialization every time
        s1 = p;
        s2 = str2;
        while();//Write the comparison process here
        p + + ;
    }
    return NULL;
}

Next we write the comparison process

#include<assert.h>
char* my_strstr(const char* str1, const char* str2,int *n)
{
    //To ensure that none of the elements inside are changed, we use const as insurance
    assert(str1 & amp; & amp; str2);
    const char* s1 = str1;
    const char* s2 = str2;
    const char* p = str1;
    while (*p)
    {
        s1 = p;
        s2 = str2;
        //When *s1 != '\0' & amp; & amp; *s2 != '\0' & amp; & amp; *s1 == *s2, we let it go backwards
        while (*s1 != '\0' & amp; & amp; *s2 != '\0' & amp; & amp; *s1 == *s2)
        {
            s1 + + ;
            s2++;
        }
        //If the middle comparison elements are all equal, *s2 will jump to '\0', indicating that the first element has been found.
        if (*s2 == '\0')
        {
            //We return a p, because p is a const when it is defined, then we need to force type conversion
            return (char*)p;
        }
        //if *s2! = '\0', we let p move to the next element and perform the next round of comparison
        p + + ;
    }
    return NULL;
}

Add a main function

#include<stdio.h>
int main()
{
    char arr[20] = "afgsfasfdasggeasvfe";
    char brr[4] = "as";
    char* ret= my_strstr(arr, brr);
    printf("%s",ret);
    return 0;
}

operation result

The operation was successful and the elements after the first as were printed.

3.strstr variant, to identify and count all substrings in a string

Obviously we added an if to the above code to determine whether the first substring is found. If it is found, it will be returned directly and will not continue to search. Let’s think about what is said when entering this if statement. , indicating that the substring has been found, right? Then we might as well define an int n=0; change return to n + +, so that it will continue to go back and record the found substring, right? We will finally return NULL, and when p reaches the null pointer, change it to return n. Doesn’t it return the number of substrings?

Note that the return type must be changed to int.

int my_strstr1(const char* str1, const char* str2)
{
    int n = 0;
    assert(str1 & amp; & amp; str2);
    const char* s1 = str1;
    const char* s2 = str2;
    const char* p = str1;
    while (*p)
    {
        s1 = p;
        s2 = str2;
        while (*s1 != '\0' & amp; & amp; *s2 != '\0' & amp; & amp; *s1 == *s2)
        {
            s1 + + ;
            s2++;
        }
        if (*s2 == '\0')
        {
            n + + ;
        }
        p + + ;
    }
    return n;
}

If there are some other requirements in the question, how should we change it

For example, if the question requires that aas cannot be counted as as, we only need to add * (p-1) not equal to a in the if statement. Or what should we do if we encounter something more complicated, such as a-s being counted as as?

Just add an if-while nesting. While is used to determine whether the elements are equal one by one. If can be used to add conditions.

int my_strstr1(const char* str1, const char* str2)
{
    int n = 0;
    assert(str1 & amp; & amp; str2);
    const char* s1 = str1;
    const char* s2 = str2;
    const char* p = str1;
    while (*p)
    {
        s1 = p;
        s2 = str2;
        while (*s1 != '\0' & amp; & amp; *s2 != '\0' & amp; & amp; *s1 == *s2)
        {
            s1 + + ;
            s2++;
        }
        if (*s1 == '-')
        {
            s1 + + ;
            while (*s1 != '\0' & amp; & amp; *s2 != '\0' & amp; & amp; *s1 == *s2)
            {
                s1 + + ;
                s2++;
            }
        }
        if (*s2 == '\0')
        {
            n + + ;
        }
        p + + ;
    }
    return n;
}

Add a main function

int main()
{
    char arr[20] = "afgsfasfda-sggeasvfe";
    char brr[4] = "as";
    int ret= my_strstr1(arr, brr);
    printf("%d",ret);
    return 0;
}

The result is still 3

4. Summary

To be honest, pointers are really difficult. Every time I do some complex pointer applications, I get dizzy. The efficiency of this function is a bit low, but it can still be used in the beginner stage. It’s a little complicated.