michael
michael

Reputation: 87

string issue with strstr()

I need to count how many times a smaller string is in bigger string with strstr(), and I know that when using strstr() it will put the pointer in the spot where the smaller string is found in bigger string. But I don't know what kind of a loop I should write to check that how many times this smaller string is presented in this bigger string? So in this case the correct answer would be 3.

My code:

#include <stdio.h>
#include <string.h>

int count_substr(const char *str, const char *sub) {
    int i = 0;
    int res;
    res = strstr(str, sub);
    if (res) {
        i++;
    }
    else {
        i = i;
    }
    return i;

}
int main(void) {
    char lol[] = "one two one twotwo three";
    char asd[] = "two";
    int ret;
    ret = count_substr(lol, asd);
    printf("%d", ret);


}

Upvotes: 1

Views: 2087

Answers (3)

user3629249
user3629249

Reputation: 16550

res = strstr(str, sub);

the variable res should be declared as char *res; rather than int res; because the function: strstr() returns a char* not a int. This error causes the compiler to output a warning message. You should have seen that warning and corrected it before posting the question.

what is this:

i = i;

supposed to accomplish?

the following proposed code:

  1. documents why each header file is being included
  2. properly calculates the number of times a substring is contained in a string, including any overlapping sub strings.
  3. appropriately includes indenting, horizontal spacing, vertical spacing, etc for ease of readability and understanding
  4. uses meaningful variable names

And now, the proposed code:

#include <stdio.h>   // printf()
#include <string.h>  // strstr()

// prototypes
int count_substr( const char *str, const char *sub );


int main(void)
{
    char lol[] = "one two one twotwo three";
    char asd[] = "two";

    int ret = count_substr( lol, asd );
    printf( "%d\n", ret );   // '\n' so immediately displayed on terminal
}


int count_substr( const char *str, const char *sub )
{
    int count = 0;
    int index = 0;
    char *oldres = NULL;
    char *newres = NULL;

    do
    {
        newres = strstr( &str[index], sub );
        index++;

        if( newres != oldres && newres )
            count++;

        oldres = newres;
    } while( oldres );

    return count;
}

Upvotes: 0

Pablo
Pablo

Reputation: 13590

You can use a while loop like this:

int count_substr(const char *str, const char *sub) {
    int cnt = 0;
    char *found;

    while(found = strstr(str, sub))
    {
        cnt++;
        str = found + 1;
    }

    return cnt;
}

The interesting part is this:

str = found + 1;

because you are not interested in the characters before the found substring, you can safely ignore them and advance str to the next character after the found substring. strstr eventually will return NULL when no substring is found or when str[0] == 0 after it reaches the end of the string.

edit

I put this in the answer because the comment section is far to restricted for longer comments.

found is a pointer to char. Whether it's pointing to a single char object or to the start of a sequence of bytes or the start of a string, depends on the context. The context here is that found is assigned with the return value of the function strstr.

man strstr

#include <string.h>

char *strstr(const char *haystack, const char *needle);

DESCRIPTION

The strstr() function finds the first occurrence of the substring needle in the string haystack. The terminating null bytes ('\0') are not compared.

RETURN VALUE

[This function returns] a pointer to the beginning of the located substring, or NULL if the substring is not found.

On success strstr returns a pointer to the location of the source where the substring is found. So found will return a pointer to "two one twotwo three".

found + 1 is pointer arithmetic and it's the same as doing &(found[1]) which will return a pointer to the next char in the sequence. found + 1 will point to "wo one twotwo three" and this pointer it will be assigned to str, so that str points to the next character after the found substring.

If I don't do that, I would have created an endless loop, because strstr would keep returning the same substring, over and over.

So the next time strstr(str, sub) is executed, found will point to "twotwo three", and found + 1 will return a pointer to "wotwo three", and so on.

In case that the substring is not found, it will return NULL the loop ends. At that point it doesn't matter that found is also pointing to NULL.

Upvotes: 2

machine_1
machine_1

Reputation: 4454

The function strstr() returns a char pointer, not an int, so the variable to be assigned its returned value should be of type char *. You can use this value to loop over a string and find the number of sub-strings in it; A while loop would suffice:

#include <stdio.h>
#include <string.h>
#include <stddef.h>

int count_substr(const char *str, const char *sub)
{
    int i = 0;
    size_t sub_len = strlen(sub);
    const char *res = strstr(str, sub);
    while (res)
    {
        i++;
        str = res + sub_len;
        res = strstr(str, sub);
    }
    return i;
}

int main(void) 
{
    char lol[] = "one two one twotwo three";
    char asd[] = "two";
    int ret = count_substr(lol, asd);
    printf("ret: %d\n", ret);
    return 0;
}

Upvotes: 1

Related Questions