как заменить подстроку в c? - PullRequest
       1

как заменить подстроку в c?

2 голосов
/ 07 сентября 2010

Этот пример работает, но я думаю, что утечка памяти.Функция, используемая в простом модуле веб-сервера и, следовательно, общая память, увеличивается при использовании этой функции.

    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;
    }

Ответы [ 4 ]

10 голосов
/ 07 сентября 2010

Одна проблема, которую я вижу, состоит в том, что если строка замены содержит строку поиска, вы будете зацикливаться вечно (пока не закончится память).

Например:

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

Кроме того, выполнение другого malloc / free каждый раз при замене одного экземпляра довольно дорого.

Лучшим подходом было бы сделать ровно 2 прохода над входной строкой:

  • первый проход, подсчитайте, сколько экземпляров строки поиска присутствует

  • теперь, когда вы знаете, сколько совпадений, вычислите длину вашего результата & malloc один раз:

    strlen (строка) + совпадения * (strlen (замена) -strlen (substr)) + 1

  • сделать второй проход через исходную строку, скопировав / заменив

1 голос
/ 10 сентября 2015

Это заменит все вхождения "str" ​​на "rep" в "src" ...

void strreplace(char *src, char *str, char *rep)
{
    char *p = strstr(src, str);
    do  
    {   
        if(p)
        {
            char buf[1024];
            memset(buf,'\0',strlen(buf));

            if(src == p)
            {
                strcpy(buf,rep);
                strcat(buf,p+strlen(str));  
            }
            else
            {
                strncpy(buf,src,strlen(src) - strlen(p));
                strcat(buf,rep);
                strcat(buf,p+strlen(str));
            }

            memset(src,'\0',strlen(src));
            strcpy(src,buf);
        }   

    }while(p && (p = strstr(src, str)));
}
1 голос
/ 07 сентября 2010

Объясните эту часть:

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

Почему вы возвращаете копию существующей строки? Это приведет к утечке памяти, и в этом нет необходимости.

Вы также никогда не освободите дубликат, если цикл while пропущен (т. Е. Условие не выполняется).

0 голосов
/ 07 сентября 2010
  • strdup не C89 / C99, поэтому ваш код => нет ANSI C
  • лучше сделать NULL-тест сразу после malloc

вот пример, только с одним новым блоком памяти:

/* 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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...