2010-09-07 2 views
1

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

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

ответ

10

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

Например:

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

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

Лучше было бы сделать ровно два проход через входную строку:

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

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

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

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

1

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

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

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

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

+0

В справедливости существующей строка всегда копируются и новая строка возвращается - либо, когда есть замена ('возврат NewStr ; ') или когда нет (' return strdup (string); '). В обоих случаях освобождение исходного ввода 'string' (а не большое имя параметра) сокращает использование памяти, предполагая, что исходный скрипт больше не нуждается в нем (или альтернативно заменяет исходную« строку »в функции и возвращает void). – Rudu

+1

Честно говоря, как программист, я бы почувствовал себя обманутым, если бы передал const char * функции и освободил ее для меня :) – EboMike

0
  • strdup не C89/C99, поэтому ваш код => не ANSI C
  • лучше сделать NULL-тест непосредственно после таНос

здесь пример, только один новый memoryblock:

/* 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; 
} 
+0

Возможно, вы захотите кэшировать значение 'strlen (old)', it может быть быстрее и вычислять его на каждой итерации. – jbernadas

+1

Строка 'p + = strlen (strcpy (p = cout + (int) p, new));' вызывает неопределенное поведение - дважды присваивается значение "p" без промежуточной точки последовательности. Тем не менее, он был запутан. –

1

Это заменит все вхождения «ул» с «репутацией» в «ЦСИ» ...

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))); 
} 
+0

Кажется работать ... –

Смежные вопросы