如何替换c中的子串?

时间:2010-09-07 14:42:34

标签: c

此示例有效,但我认为内存泄漏。如果使用此功能,则在简单Web服务器模块中使用的函数会因共享内存而增加。

    char *str_replace ( const char *string, const char *substr, const char *replacement ){
      char *tok = NULL;
      char *newstr = NULL;
      char *oldstr = NULL;
      if ( substr == NULL || replacement == NULL ) return strdup (string);
      newstr = strdup (string);
      while ( (tok = strstr ( newstr, substr ))){
        oldstr = newstr;
        newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 );
        memset(newstr,0,strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1);
        if ( newstr == NULL ){
          free (oldstr);
          return NULL;
        }
        memcpy ( newstr, oldstr, tok - oldstr );
        memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) );
        memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) );
        memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 );
        free (oldstr);
      }
      return newstr;
    }

3 个答案:

答案 0 :(得分:10)

我可以看到的一个问题是,如果替换字符串包含搜索字符串,您将永远循环(直到内存不足)。

例如:

char *result = str_replace("abc", "a", "aa");

另外,每次更换一个实例时再做一次malloc / free是非常昂贵的。

更好的方法是在输入字符串上完成2次传递:

  • 第一遍,计算搜索字符串的实例数

  • 现在您知道了多少匹配,计算结果的长度& malloc曾经:

    strlen(string)+ matches *(strlen(replacement)-strlen(substr))+ 1

  • 再次通过源字符串,复制/替换

答案 1 :(得分:1)

解释这一部分:

if ( substr == NULL || replacement == NULL ) return strdup (string);

为什么要返回现有字符串的副本?这会泄漏内存,而且没必要。

如果跳过while循环(即从未满足条件),也永远不会释放副本。

答案 2 :(得分:0)

  • strdup不是C89 / C99,因此您的代码=>没有ANSI C
  • 在malloc
  • 之后更好地直接进行NULL测试

这里有一个例子,只有一个新的内存块:

/* precondition: s!=0, old!=0, new!=0 */
char *str_replace(const char *s, const char *old, const char *new)
{
  size_t slen = strlen(s)+1;
  char *cout = malloc(slen), *p=cout;
  if( !p )
    return 0;
  while( *s )
    if( !strncmp(s, old, strlen(old)) )
    {
      p  -= cout;
      cout= realloc(cout, slen += strlen(new)-strlen(old) );
      p  += strlen( strcpy(p=cout+(int)p, new) );
      s  += strlen(old);
    }
    else
     *p++=*s++;

  *p=0;
  return cout;
}