Search code examples
cfor-loopnested-loopscs50c-strings

My algorithm for replacing characters in string is not working


For example when I input in the terminal

hello there

it prints

gmllg mgmkm

instead of printing

itssg zitkt

which is not supposed to happen.

Another example is when I input in the terminal

abcdefghijklmnopqrstuvwxyz

it prints

jvmkmnbgghaldfghjklmbcvbnm

the last 5 characters are right but its supposed to print

qwertyuiopasdfghjklzxcvbnm

Anyways I can fix this?

Here is the code below

#include <cs50.h>
#include <stdio.h>
#include <string.h>
void replace_char(string text, string replace, string new);
int main(void){

    string message = get_string("Type message: ");
    string Alpha = "abcdefghijklmnopqrstuvwxyz";
    string Key  =  "qwertyuiopasdfghjklzxcvbnm";
    replace_char(message, Alpha, Key);
    printf("%s\n", message);
}
void replace_char(string text, string replace, string new){

    int strl = strlen(text);
    int h;
    int p;
    for (h = 0; h < strl; h++){
        for (p = 0; p < 26; p++)
        if (text[h] == replace[p])
        text[h] = new[p];}
}

Solution

  • The problem is that after you've replaced the character you continue searching and may therefore replace the character you just put there. This may happen multiple times. When you find a match, you need to break out of the loop:

    void replace_char(string text, string replace, string new){
        int strl = strlen(text);
    
        for (int h = 0; h < strl; h++){
            for (p = 0; p < 26; p++) {
                if (text[h] == replace[p]) {
                    text[h] = new[p];
                    break;                   // break out
                }
            }
        }
    }
    

    An even simpler version would be to just look up the character in the replacement string directly. This works if the characters in replace are in a contiguous range (and they are 26 of them as you've hardcoded):

    void replace_char(string text, string replace, string new){
        int strl = strlen(text);
    
        for (int h = 0; h < strl; h++){
            if(text[h] >= replace[0] && text[h] <= replace[25])
                text[h] = new[text[h] - replace[0]];
        }
    }
    

    Or, make sure that replace is a contiguous range by taking the first and last character in the range instead:

    #include <assert.h>
    
    void replace_char(string text, char first, char last, string new) {
        int strl = strlen(text);
    
        assert(strlen(new) >= last - first);
    
        for (int h = 0; h < strl; h++) {
            if (text[h] >= first && text[h] <= last)
                text[h] = new[text[h] - first];
        }
    }
    

    and call it like so:

    replace_char(message, 'a', 'z', Key);