我使用以下函数替换给定字符串中的子字符串
void ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *result = NULL;
int i, cnt = 0;
int tolen = strlen(to);
int fromlen = strlen(from);
if (*inputString == NULL)
return;
// Counting the number of times old word
// occur in the string
for (i = 0; (*inputString)[i] != '\0'; i++)
{
if (strstr((&(*inputString)[i]), from) == &(*inputString)[i])
{
cnt++;
// Jumping to index after the old word.
i += fromlen - 1;
}
}
// Making new string of enough length
result = (char *)malloc(i + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return;
memset(result, 0, i + cnt * (tolen - fromlen) + 1);
i = 0;
while (&(*inputString))
{
// compare the substring with the result
if (strstr(*inputString, from) == *inputString)
{
strncpy(&result[i], to, strlen(to));
i += tolen;
*inputString += fromlen;
}
else
{
result[i++] = (*inputString)[0];
if ((*inputString)[1] == '\0')
break;
*inputString += 1;
}
}
result[i] = '\0';
*inputString = result;
return;
}
上述功能的问题是内存泄漏。无论为inputString分配什么内存,都会在此行之后丢失。
*inputString = result;
因为我正在使用strstr和inputString *inputString += fromlen;
的移动指针,inputString在上面的行之前指向NULL。那么如何在这里处理内存泄漏。
注意:我不想返回在函数内分配的新内存。我需要根据新的长度改变inputString内存。
答案 0 :(得分:1)
您应该使用局部变量迭代输入字符串,并避免在释放前一个字符串的最后一步之前修改*inputString
,并将其替换为新分配的指针。
使用当前API,必须使用指向分配有ReplaceSubStr
或类似内容的块的指针的地址调用malloc()
。将指针传递给本地存储或字符串文字将具有未定义的行为。
以下是一些需要改进的想法:
您可以返回新字符串并将其留给调用者以释放前一个字符串。在这种情况下,您将按值而不是地址:
获取输入字符串char *ReplaceSubStr(const char *inputString, const char *from, const char *to);
如果from
字符串为空,则应在输入字符串的每个字符之间插入to
字符串或不执行任何操作。发布后,您的代码对此边框情况具有未定义的行为。
from
是否存在i
字符串,请使用memcmp
代替strstr
。cnt
为0,则无需执行任何操作。result
数组。strncpy()
。此函数具有反直觉的语义,并且经常被误用。阅读本文:https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/ 以下是改进版本:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int ReplaceSubStr(char **inputString, const char *from, const char *to) {
char *input = *inputString;
char *p, *q, *result;
size_t cnt;
size_t tolen = strlen(to);
size_t fromlen = strlen(from);
if (input == NULL || fromlen == 0)
return 0;
// Counting the number of times old word occurs in the string
for (cnt = 0, p = input; (p = strstr(p, from)) != NULL; cnt++) {
p += fromlen;
}
if (cnt == 0) // no occurrence, nothing to do.
return 0;
// Making new string of enough length
result = (char *)malloc(strlen(input) + cnt * (tolen - fromlen) + 1);
if (result == NULL)
return -1;
for (p = input, q = result;;) {
char *p0 = p;
p = strstr(p, from);
if (p == NULL) {
strcpy(q, p0);
break;
}
memcpy(q, p0, p - p0);
q += p - p0;
memcpy(q, to, tolen);
q += tolen;
p += fromlen;
}
free(*inputString);
*inputString = result;
return 0;
}
int main() {
char *p = strdup("Hello world!");
ReplaceSubStr(&p, "l", "");
printf("%s\n", p); // prints Heo word!
free(p);
return 0;
}
答案 1 :(得分:0)
你显然无法释放输入,因为它可能是一个文字,一些你无法控制的记忆。这将比现在更加削弱你的功能。
您可以返回inputString
的旧值,以便在需要时可以将其释放。
char *ReplaceSubStr(char **inputString, const char *from, const char *to)
{
char *old_string = *inputString;
...
return old_string;
}
如果需要,调用者有责任释放old_string
的内容。
如果不需要(我们必须通过将有效的可写数组分配给指针以便能够传递此指针来解决char **
输入:
char input[]="hello world";
char *ptr = input;
ReplaceSubStr(&ptr, "hello", "hi");
// input is now "hi world" in a different location
free(ptr); // when replaced string isn't needed
如果需要:
char *input = strdup("hello world");
char *old_input = ReplaceSubStr(&input, "hello", "hi");
free(old_input);
或只是
free(ReplaceSubStr(&input, "hello", "hi"));
然后总是(当不需要替换字符串时):
free(input);
唯一的限制是你不能使用常量字符串文字作为输入(const char *input = "hello world"
)因为原型&amp;可能会返回char *
以传递给free
。