function replace substring returns incorrect answer

本秂侑毒 提交于 2020-07-16 04:24:21

问题


I have a program replacing a substring in a string. The idea is to find the string_to_be_replaced in original_string, then realloc the new_string and connect it to replace_by string. It works for some cases but in some cases like below, it return wrong answer:

Input:

abc def ghi //orginal string

(a blank space) //string to be replaced

1234 //replace by

Output:

abc1234defT123ghi

Expected output:

abc1234def1234ghi

When I debug it, I saw a wrong character has been filled in the new_string after the first replacement had been done.

Please tell me why does this happen and how to fix it. Any help would be appreciated.

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

void fgetsWithoutNewline(char *s, size_t maxCount, FILE *fp);
bool sameString(char *original_tring, char *string_to_be_searched, size_t start);
char *replaceString(char *original_tring, char *string_to_be_replaced, char *replace_by);

int main()
{
    char *original_string = malloc(100);
    fgetsWithoutNewline(original_string, 99, stdin);

    char *string_to_be_replaced = malloc(100);
    fgetsWithoutNewline(string_to_be_replaced, 99, stdin);

    char *replace_by = malloc(100);
    fgetsWithoutNewline(replace_by, 99, stdin);

    char *s = replaceString(original_string, string_to_be_replaced, replace_by);
    printf("%s", s);

    free(original_string);
    free(string_to_be_replaced);
    free(replace_by);
    return 0;
}

void fgetsWithoutNewline(char *s, size_t maxCount, FILE *fp)
{
    if (fgets(s, maxCount, fp))
    {
        s[strcspn(s, "\n")] = '\0';
    }
    return;
}

char *replaceString(char *original_tring, char *string_to_be_replaced, char *replace_by)
{
    if (!original_tring || !string_to_be_replaced || !replace_by)
    {
        return NULL;
    }
    char *new_string = malloc(strlen(original_tring));

    for (size_t i = 0, j = 0; i < strlen(original_tring); i++, j++)
    {
        if (sameString(original_tring, string_to_be_replaced, i))
        {
            new_string = realloc(new_string, strlen(new_string) + strlen(replace_by) - strlen(string_to_be_replaced));
            strcat(new_string, replace_by);
            i += strlen(string_to_be_replaced) - 1;  // i and j use to track the last character of original string and new string
            j += strlen(replace_by) - 1;
        }
        else
        {
            new_string[j] = original_tring[i];
        }
    }
    return new_string;
}

bool sameString(char *original_tring, char *string_to_be_searched, size_t start)
{
    if (strlen(string_to_be_searched) + start > strlen(original_tring))
    {
        return false;
    }
    size_t end = strlen(string_to_be_searched) + start;
    for (size_t i = start, j = 0; i < end; i++, j++)
    {
        if (original_tring[i] != string_to_be_searched[j])
        {
            return false;
        }
    }
    return true;
}

回答1:


Well the symptoms are clear, the string is not being null terminated.

Try the follwing:

Live demo

char *replaceString(char *original_tring, char *string_to_be_replaced, const char *replace_by)
{
    if (!original_tring || !string_to_be_replaced || !replace_by)
    {
        return NULL;
    }
    char *new_string = malloc(strlen(original_tring));

    for (size_t i = 0, j = 0; i < strlen(original_tring); i++, j++)
    {
        if (sameString(original_tring, string_to_be_replaced, i))
        {
            new_string = realloc(new_string, strlen(new_string) + strlen(replace_by) - strlen(string_to_be_replaced));
            strcat(new_string, replace_by);
            i += strlen(string_to_be_replaced) - 1;
            j += strlen(replace_by) - 1;
        }
        else
        {
            new_string[j] = original_tring[i];
        }
        new_string[j + 1] = '\0'; //here
    }  
    return new_string;
}



回答2:


The problem is that you aren't adding the required nul-terminator character(s) to your new_string buffer (in the replace_string function). On systems that, just by chance, fill any new data 'created' by malloc or realloc with zeros, this will be hard to find; but this is not the standard behaviour, and you should explicitly ensure the nul-terminator is always there.

For the initial allocation of new_string, this could be done using the calloc function; however, as you (probably) call realloc to increase the size of the buffer at least once, you will have to make sure that the newly-added memory also has the nul, so you only really need to add that terminator at the of every run of the for loop:

char* replaceString(char* original_tring, char* string_to_be_replaced, char* replace_by)
{
    if (!original_tring || !string_to_be_replaced || !replace_by) {
        return NULL;
    }
    char* new_string = malloc(strlen(original_tring));
    for (size_t i = 0, j = 0; i < strlen(original_tring); i++, j++) {
        if (sameString(original_tring, string_to_be_replaced, i)) {
            new_string = realloc(new_string, strlen(new_string) + strlen(replace_by) - strlen(string_to_be_replaced));
            strcat(new_string, replace_by);
            i += strlen(string_to_be_replaced) - 1;  // i and j use to track the last character of original string and new string
            j += strlen(replace_by) - 1;
        }
        else {
            new_string[j] = original_tring[i];
        }
        new_string[j + 1] = '\0';/// Add new nul-terminator!
    }
    return new_string;
}



回答3:


Your function (abstracting from the missing nul terminator) is very inefficient.

Below you have the functions

This one uses the same string to store the result:

char *stringreplace(char *haystack, const char *needle, const char *replace)
{
    size_t needleLen = strlen(needle);
    size_t replaceLen = strlen(replace);
    char *wrk = haystack;
    char *end = haystack + strlen(haystack);



    while((wrk = strstr(wrk, needle)))
    {
        memmove(wrk + replaceLen, wrk + needleLen, end - wrk + 1);
        memcpy(wrk, replace, replaceLen);
        wrk += replaceLen;
        end += replaceLen - needleLen;
    }
    return haystack;
}

This one is using dynamic allocation. Note that on many systems malloc and especially realloc are very expensive operation and it is often worth tto traverse the string twice and call only one malloc knowing the size of the resulting string.

char *dupstringreplace(const char *haystack, const char *needle, const char *replace)
{
    char *newhaystack = NULL;
    const char *wrk = haystack;
    char *newwrk;
    ssize_t occurences = 0;
    size_t needleLen = strlen(needle);
    size_t replaceLen = strlen(replace);

    while((wrk = strstr(wrk, needle)))
    {
        occurences++;
        wrk += needleLen;
    }
    newhaystack = malloc(strlen(haystack) + occurences * ((ssize_t)replaceLen - (ssize_t)needleLen) + 1);
    wrk = haystack;
    newwrk = newhaystack;
    while((wrk = strstr(wrk, needle)))
    {
        memcpy(newwrk, haystack, wrk - haystack);
        newwrk += wrk - haystack;
        memcpy(newwrk, replace, replaceLen);
        newwrk += replaceLen;
        wrk += needleLen;
        haystack = wrk;
    }
    strcpy(newwrk, haystack);
    return newhaystack;
}

godbolt



来源:https://stackoverflow.com/questions/62486537/function-replace-substring-returns-incorrect-answer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!