¿Cómo reemplazar la subcadena en c?

Este ejemplo funciona pero creo que la memoria se pierde. La función utilizada en el módulo de servidor web simple y, por lo tanto, la memoria compartida aumenta si utiliza esta función.

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

Un problema que puedo ver es que si la cadena de reemplazo contiene la cadena de búsqueda, se repetirá (hasta que se quede sin memoria).

Por ejemplo:

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

Además, hacer otro malloc / free cada vez que reemplace una instancia es bastante costoso.

Un mejor enfoque sería hacer exactamente 2 pasadas sobre la cadena de entrada:

  • la primera pasada, cuente cuántas instancias de la cadena de búsqueda están presentes

  • Ahora que sabe cuántas coincidencias, calcule la longitud de su resultado y malloc una vez:

    strlen (cadena) + coincidencias * (strlen (reemplazo) -strlen (substr)) + 1

  • hacer una segunda pasada a través de la cadena de origen, copiando / reemplazando

Explique esta parte:

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

¿Por qué devuelves una copia de la cadena existente? Esto perderá memoria, y es innecesario.

También nunca libera el duplicado si se omite el bucle while (es decir, la condición nunca se cumple).

Esto reemplazará toda la aparición de “str” ​​con “rep” en “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))); } 
  • strdup no es C89 / C99, por lo tanto, su código => no ANSI C
  • Mejor hacer el test NULL directo después de malloc.

Aquí un ejemplo, solo con un nuevo bloque de memoria:

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