问题
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