2010-09-07 21 views
1

這個例子可以工作,但我認爲內存泄漏。如果使用此功能,則在簡單Web服務器模塊中使用的功能和共享內存會增加。 如何替換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"); 

而且,做又是另外的malloc /免費每次更換一個實例是相當昂貴的。

一個更好的辦法是在輸入字符串做的正是2遍:

  • 第一遍,算上搜索字符串多少實例存在

  • 現在您知道了如何很多比賽,你的計算結果的長度&的malloc一次:

    的strlen(字符串)+匹配*(strlen的(替代)-strlen(SUBSTR))+ 1

  • 使通過源串中的第二遍中,複製/更換

1

解釋這一部分:

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

你爲什麼返回現有字符串的副本?這會泄漏內存,這是沒有必要的。

如果跳過while循環(即從未滿足條件),您也永遠不會釋放重複項。

+0

公平現有的字符串時,始終複製和一個新的字符串返回 - 無論是當有替代品('回報中newstr ;')或者沒有時('return strdup(string);')。在這兩種情況下,假設原始腳本不再需要它(或者替換函數中的原始「字符串」並返回void),釋放原始輸入'string'(不是一個很好的參數名稱)會減少內存使用量。 – Rudu 2010-09-07 14:56:29

+1

很誠實,作爲一名程序員,如果我將一個const char *傳遞給一個函數,並且它爲我騰出空間,我會覺得有點被愚弄:) – EboMike 2010-09-07 15:18:36

0
  • 的strdup不是C89/C99,因此代碼=>無ANSI C
  • 更好使NULL測試直接後malloc的

這裏的例子中,只有一個新的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)'的值,它可能會更快並且在每次迭代中計算它。 – jbernadas 2010-09-07 17:57:40

+1

行'p + = strlen(strcpy(p = cout +(int)p,new));'會導致未定義的行爲 - 將兩次賦值給「p」而沒有中間的序列點。雖然很好地混淆了。 – 2010-09-08 03:44:55

1

這將取代「海峽」與「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))); 
} 
+0

似乎工作... – 2016-04-23 22:53:09