简体   繁体   中英

Create the strstr function in C from scratch, but with modified strings

To summarize, if the function is given arguments char *str1 = "Watch out the streets?"; char *str2 = "street?";, it should return a pointer in str1 to the first instance of "street", starting from s.

I am completely stuck and appreciate any help. I have a feeling my problem is with pointers. I'm a beginner as you might imagine.

I just edited the code to my latest attempt. I am very close, but cannot still find the idea to modify the first string.

Output image:

输出图像

    const char *qstr_strstr(const char *str1, const char *str2) {
    int j = 0;
    char newstr2[256];
    while (str2[j]) {  
        if (str2[j] == '?') {  
            break;  
        } else {
            newstr2[j] = str2[j];
        }
        j++;
    }
    newstr2[j] = '\0';
    size_t n = strlen(newstr2);
    while(*str1) {
        if (!memcmp(str1++, newstr2, n)) {
            return (str1 - 1);
        }
    }
    return NULL;
}

You are heading in the right direction, and you are starting to think about stepping through stings correctly, but you are getting wrapped up in your use of any additional string -- there is no need for that.

When you are analyzing stings and substrings, all you care about is:

  1. the index (position) within the original string (to iterate);
  2. whether you have found the beginning of the substring yet (if so set flag indicating in word matching chars); and
  3. whether you make it all the way to the end of the substring while your flag is set (if you do, you have found your substring). Otherwise, if there is a mismatch in characters before reaching the end, unset your flag and keep going. Repeat until you run out of str1 .

Complicating your case here is the Red-Herring '?' character. You can either use it as a test for end-of-substring, or ignore it altogether. Your goal is to locate str2 "street" within str1 "... streets?" . You would generally use ispunct() from ctype.h to identify '?' as a non-word character and not part of the string anyway. Here, you can simply check for '?' in a similar way that you would check for '\0' to mark end-of-string .

Putting it altogether and not using any of the string.h or ctype.h functions, you could do:

#include <stdio.h>

const char *qstr_strstr (const char *str1, const char *str2)
{
    int i = 0, instr2 = 0, ndx = 0;         /* str1 index, in-str2 flag, str2 index */
    
    if (str1 == NULL || str2 == NULL)       /* validte both str1 and str2 not NULL */
        return NULL;
    
    do {    /* loop over each char in str1 */
        /* if in str2 and (at end or at '?') */
        if (instr2 && (!str2[ndx] || str2[ndx] == '?'))
            return &str1[i-ndx];            /* return address in str1 to start of str2 */
        /* if char in str1 and str2 equal */
        if (str1[i] == str2[ndx]) {
            ndx += 1;                       /* increment str2 index */
            instr2 = 1;                     /* set in-str2 flag true (done each time) */
        }
        else    /* otherwise chars not equal */
            ndx = instr2 = 0;               /* reset str2 index, set in-str2 flag false */
    } while (str1[i++]);                    /* includes \0, allows match at end of both */
    
    return NULL;
}

int main (void) {
    
    const char *str1 = "Watch of the streets?",
               *str2 = "street?",
               *ptr = qstr_strstr (str1, str2);
    
    if (ptr) {
        size_t i = ptr - str1;
        printf ("ptr       : %s\nptr addr  : %p\n---\n"
                "&str1[%zu] : %s\n&str1[%zu] : %p\n",
                ptr, (void*)ptr, i, str1 + i, i, (void*)(str1 + i));
    }
}

Example Use/Output

Outputting the string and adderss retuned by qstr_strstr() as well as the address of that string and address located within the original str1 you would have:

$ ./bin/strstrawk
ptr       : streets?
ptr addr  : 0x4006c1
---
&str1[13] : streets?
&str1[13] : 0x4006c1

You can further copy just the substring street from the address in str1 or whatever else you need to do. Look things over and let me know if you have further questions.


Edit Based On Picture Added

If you want to output just the characters before the '?'from the pointer returned by qstr_strstr() , then you can do that trivially by using the precision modifier with the "%s" output conversion specifier in your printf format string and limit the number of characters output to just the number before the '?' in str2 . Your format conversion specifier would look like "%.*s" where it expects 2 arguments, the first of type int being the number of characters, and the second the string.

In the case above the arguments would be:

            (int)strcspn (str2, "?"), ptr

Where strcspn() returns the number of characters before the '?'in str2 (cast to int ) and ptr the return from qstr_strstr() . Changing the code above you would have:

...
#include <string.h>
...
        printf ("ptr       : %.*s\nptr addr  : %p\n---\n"
                "&str1[%zu] : %s\n&str1[%zu] : %p\n",
                (int)strcspn (str2, "?"), ptr, (void*)ptr, 
                i, str1 + i, i, (void*)(str1 + i));

(the remaining code is unchanged)

$ ./bin/strstrawk
ptr       : street
ptr addr  : 0x4006c1
---
&str1[13] : streets?
&str1[13] : 0x4006c1

Where the output using ptr as the string and the length from str2 is not "street" .

Let me know if you have further questions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM