2010-09-07 4 views
1

Cet exemple fonctionne mais je pense que la mémoire fuit. La fonction utilisée dans le module serveur web simple et donc la mémoire partagée augmente si vous utilisez cette fonction. comment remplacer la sous-chaîne dans 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; 
    } 

Répondre

10

Un problème que je peux voir est que si la chaîne de remplacement contient la chaîne de recherche, vous bouclez pour toujours (jusqu'à ce que vous manquiez de mémoire).

Par exemple:

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

En outre, faire une autre malloc/gratuit chaque fois que vous remplacez une instance est assez cher.

Une meilleure approche serait de faire exactement 2 passe sur la chaîne d'entrée:

  • la première passe, compter le nombre d'occurrences de la chaîne de recherche sont présents

  • maintenant que vous savez comment beaucoup de matches, calculer la longueur de votre résultat & malloc fois:

    strlen (string) + * matchs (strlen (remplacement) -strlen (substr)) + 1

  • faire une deuxième passe à travers la chaîne source, copier/remplacer

1

Expliquer cette partie:

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

Pourquoi vous renvoyer une copie de la chaîne existante? Cela entraînera une fuite de mémoire et ce n'est pas nécessaire.

Vous ne pouvez également jamais libérer le doublon si la boucle while est ignorée (c'est-à-dire que la condition n'est jamais remplie).

+0

En toute justice la chaîne existante est toujours copiée et une nouvelle chaîne retournée - soit quand il y a des remplacements ('retour newstr ; ') ou lorsqu'il n'y en a pas (' return strdup (string); '). Dans les deux cas, libérer l'entrée d'origine 'string' (pas un grand nom de paramètre) réduit l'utilisation de la mémoire, en supposant que le script original n'en a plus besoin (ou bien remplacer la chaîne originale dans la fonction et retourner void). – Rudu

+1

Très honnêtement, en tant que programmeur, je me sentirais dupé si je transmettais un const char * à une fonction et que cela me libère :) – EboMike

0
  • strdup n'est pas C89/C99, donc votre code => pas ANSI C
  • mieux faire le après directement NULL test malloc

ici un exemple, avec une seule nouvelle 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

Vous pourriez vouloir mettre en cache la valeur de 'strlen (old)', pourrait être plus rapide et le calculer à chaque itération. – jbernadas

+1

La ligne 'p + = strlen (strcpy (p = cout + (int) p, nouveau));' provoque un comportement indéfini - assignant deux fois à "p" sans un point de séquence intermédiaire. Bien obscurément, cependant. –

1

Cela remplacera toute occurrence de « str » avec « représentant » dans « 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

Ça semble fonctionner ... –

Questions connexes