Nascosto
Nascosto

Reputation: 13

Removing array of occurrences from string in C

I'm having looping issues with my code. I have a method that takes in two char arrays (phrase, characters). The characters array holds characters that must be read individually and compared to the phrase. If it matches, every occurrence of the character will be removed from the phrase.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//This method has two parameters: (str, c)
//It will remove all occurences of var 'c'
//inside of 'str'
char * rmstr(char * c, char * str) {

    //Declare counters and pointers
    int stemp = 0;
    int ctemp = 0; 
    char *p = str;
    char *d = c;
    //Retrieve str count
    while(str[stemp] != '\0') {
        stemp++;
    }
    //Retrieve c count
    while(c[ctemp] != '\0') {
        ctemp++;
    }
    //Output information
    printf("String Count: %d\n",stemp);
    printf("Character Count: %d\n",ctemp);
    //Iterate through arrays
    for (int i = 0; i != stemp; i++) {
        for (int j = 0; j != ctemp; j++) {
            if (c[j] != str[i]){
                *p++ = str[i];
            } 
                break;
        }
        printf("%s\n",str);
    }
    *p = 0;
    return str;
}

int main()
{
    char c[256] = "ema";
    char input[256] = "Great message!";
    char *result = rmstr(c, input);
    printf("%s", result);
    return 0;
}

In this case, the input would be "Great Message!" and the character I'd like to remove all occurrences of the characters: e, m, a (As specified in main).

Using the code as it is above, the output is as follows:

Grat mssag!

It is only looping through 1 iteration and removing 'e'. I would like it to loop through 'm' and 'a' as well.

Upvotes: 0

Views: 343

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84559

After you fix your break; that was causing your inner loop to exit, it may make sense to reorder your loops and loop over the chars to remove while checking against the characters in str. This is more of a convenience allowing you to shuffle each character down by one in str if it matches a character is c. If you are using the functions in string.h like memmove to move characters down, it doesn't really matter.

A simple implementation using only pointers to manually work through str removing all chars in c could look something like the following:

#include <stdio.h>

char *rmstr (char *str, const char *chars)
{
    const char *c = chars;          /* set pointer to beginning of chars */
    while (*c) {                    /* loop over all chars with c */
        char *p = str;              /* set pointer to str */
        while (*p) {                /* loop over each char in str */
            if (*p == *c) {         /* if char in str should be removed */
                char *sp = p,       /* set start pointer at p */
                    *ep = p + 1;    /* set end pointer at p + 1 */
                do
                    *sp++ = *ep;    /* copy end to start to end of str */
                while (*ep++);      /* (nul-char copied on last iteration) */
            }
            p++;                    /* advance to next char in str */
        }
        c++;                        /* advance to next char in chars */
    }
    return str;     /* return modified str */
}

int main (void) {

    char c[] = "ema";
    char input[] = "Great message!";

    printf ("original: %s\n", input);
    printf ("modified: %s\n", rmstr (input, c));

    return 0;
}

(there are many ways to do this -- how is largely up to you. whether you use pointers as above, or get the lengths and use string-indexes is also a matter of choice)

Example Use/Output

$ ./bin/rmcharsinstr
original: Great message!
modified: Grt ssg!

If you did want to use memmove (to address the overlapping nature of the source and destination) to move the remaining characters in str down by one each time the character in str matches a character in c, you could leave the loops in your original order, e.g.

#include <string.h>

char *rmstr (char *str, const char *chars)
{
    char *p = str;                  /* set pointer to str */
    while (*p) {                    /* loop over each char in str */
        const char *c = chars;      /* set pointer to beginning of chars */
        while (*c) {                /* loop over all chars with c */
            while (*c == *p) {      /* while the character matches */
                memmove (p, p + 1, strlen (p)); /* shuffle down by 1 */
                c = chars;          /* reset c = chars to check next */
            }
            c++;                    /* advance to next char in chars */
        }
        p++;                        /* advance to next char in str */
    }
    return str;     /* return modified str */
}

(make sure you understand why you must reset c = chars; in this case)

Finally, if you really wanted the shorthand way of doing it, you could use strpbrk and memmove and reduce your function to:

#include <string.h>

char *rmstr (char *str, const char *chars)
{
    /* simply loop using strpbrk removing the character found */
    for (char *p = strpbrk (str, chars); p; p = strpbrk (str, chars))
        memmove (p, p+1, strlen(p));

    return str;     /* return modified str */
}

(there is always more than one way to skin-the-cat in C)

The output is the same. Look things over here and let me know if you have further questions.

Upvotes: 1

Related Questions