Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Distorsion en 27 Octubre 2012, 05:06 am



Título: Split en C
Publicado por: Distorsion en 27 Octubre 2012, 05:06 am
Buenas,

He estado buscando información y lo que más me ha convencido es este código de Ferchu, que es justo lo que necesito, separar por una palabra, no solo un carácter:

Código:
#include <stdio.h>
#include <windows.h>
 
int separar(char ***vector, char *cadena, char *buscada);
 
int main(int argc, char *argv[])
{
 
    char frase[]="Holasss999 como estas 999freeze??? 999 :p999a999b999999c999d99aaaa999";
    char **palabras;
    int cant,i;
 
    cant = separar(&palabras,frase,"999");
 
    for(i=0;palabras[i];i++)printf("%s\n",palabras[i]);
    system("PAUSE");
    return EXIT_SUCCESS;
}
 
 
int separar(char ***vector, char *cadena, char *buscada){
 
    char **palabras;
    int tam,i,iant=0,n=0,cantidad=1;
    int tamtotal,tamfrase;
 
    tamtotal=strlen(cadena);
    tam=strlen(buscada);
 
    // recorro primero una vez para contar las partes, para no complicarla con realloc.
    for(i=0;i<tamtotal;i++){
                            while((cadena[i+n]==buscada[n])&&(n<tam))n++;
                            if(n==tam)cantidad++; 
                            n=0;
                            }
 
    palabras=(char **)malloc(cantidad * sizeof(char **));
    cantidad=0;
 
    for(i=0;i<tamtotal;i++){
                            while((cadena[i+n]==buscada[n])&&(n<tam))n++;     
                            if(n==tam){
                                   tamfrase=i-iant;
                                   palabras[cantidad]=(char*)malloc(tamfrase);
                                   memcpy(palabras[cantidad],&cadena[iant],tamfrase);
                                   palabras[cantidad][i-iant]=0;
                                   iant=i+tam;
                                   cantidad++;
                                   i=i+tam;
                            }
                            n=0;
    }
 
    tamfrase=i-iant;
    palabras[cantidad]=(char*)malloc(tamfrase);
    memcpy(palabras[cantidad],&cadena[iant],tamfrase);
    palabras[cantidad][tamfrase]=0;
    palabras[cantidad+1]=0;
    *vector=palabras;
 
    return cantidad; 
}
 

El problema es que al usar la función Separar me da cuelgues aleatorios.
Los cuelgues me los da al usarla para filtrar conexiones html, buscando cadenas en el protocolo.

La verdad no se porque, si alguien le ve el fallo...


 ;D


Título: Re: Split en C
Publicado por: rir3760 en 27 Octubre 2012, 19:58 pm
Los problemas con la función son tres:

* El primero ocurre al contar las instancias del separador, supongamos que este es "999" y la cadena a tasajear inicia con "99999". En base a ello el primer bucle de la función:
Código
  1. for(i = 0; i < tamtotal; i++) {
  2.   while((cadena[i + n] == buscada[n]) && (n < tam))
  3.      n++;
  4.   if (n == tam)
  5.      cantidad++;
  6.   n = 0;
  7. }
Contara tres instancias del separador cuando solo hay una, eso debido a que avanza por la cadena carácter por carácter.

* El segundo es no verificar si el valor de la variable:
Código
  1. tamfrase = i - iant;
Es igual a cero (eso ocurre si hay dos separadores lado a lado), a continuación se trata de reservar memoria con "malloc" y no es valida una reserva de cero.

* El tercero, cuando se hace la reserva de memoria se debe reservar un carácter adicional para el indicador de fin de cadena (el '\0').

No es difícil realizar los cambios, lo podrías tomar como un ejercicio.

Un saludo


Título: Re: Split en C
Publicado por: Distorsion en 28 Octubre 2012, 00:58 am
Mil  gracias macho.

Los dos primeros los descarto, porque al usar de separador una palabra, es imposible en el contexto donde lo ejecuto que hayan dos seguidas.

Intentare reservar un carácter extra y comento el resultado.

 ;-)


Título: Re: Split en C
Publicado por: Distorsion en 28 Octubre 2012, 02:23 am
Listo, ya no hay cuelgues aleatorios.

 ;-)


Título: Re: Split en C
Publicado por: rir3760 en 29 Octubre 2012, 03:18 am
Otra forma, basada en aritmética de punteros y la función "strstr" (prototipo en <string.h>), es (falta la validación de errores):
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. char **separar(char const *cad, char const *sep, int *num_elem);
  6.  
  7. int main(void)
  8. {
  9.   char const *linea = "Holasss999 como estas 999freeze??? 999 :p999a999b999999c999d99aaaa999";
  10.   char **elem;
  11.   int num_elem;
  12.   int i;
  13.  
  14.   elem = separar(linea, "999", &num_elem);
  15.   for (i = 0; i < num_elem; i++)
  16.      printf("elem[%2d] == \"%s\"\n", i, elem[i]);
  17.  
  18.   for (i = 0; i < num_elem; i++)
  19.      free(elem[i]);
  20.   free(elem);
  21.  
  22.   return EXIT_SUCCESS;
  23. }
  24.  
  25. char **separar(char const *cad, char const *sep, int *num_elem)
  26. {
  27.   char **elem;
  28.   char *p;
  29.   int i;
  30.  
  31.   size_t nc_sep = strlen(sep);
  32.  
  33.   elem = malloc((strlen(cad) + nc_sep) / (nc_sep + 1) * sizeof *elem);
  34.  
  35.   for (i = 0; (p = strstr(cad, sep)) != NULL; cad = p + nc_sep){
  36.      if (p != cad){
  37.         elem[i] = malloc(p - cad + 1);
  38.         sprintf(elem[i], "%.*s", p - cad, cad);
  39.         i++;
  40.      }
  41.   }
  42.   if (*cad != '\0'){
  43.      elem[i] = malloc(strlen(cad) + 1);
  44.      strcpy(elem[i], cad);
  45.      i++;
  46.   }
  47.   *num_elem = i;
  48.  
  49.   return realloc(elem, i * sizeof *elem);
  50. }

Un saludo