Split en C

Iniciado por Distorsion, 27 Octubre 2012, 05:06 AM

0 Miembros y 1 Visitante están viendo este tema.

Distorsion

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:

#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

rir3760

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:
for(i = 0; i < tamtotal; i++) {
   while((cadena[i + n] == buscada[n]) && (n < tam))
      n++;
   if (n == tam)
      cantidad++;
   n = 0;
}

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:
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
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language

Distorsion

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.

;-)

Distorsion

Listo, ya no hay cuelgues aleatorios.

;-)

rir3760

Otra forma, basada en aritmética de punteros y la función "strstr" (prototipo en <string.h>), es (falta la validación de errores):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char **separar(char const *cad, char const *sep, int *num_elem);

int main(void)
{
   char const *linea = "Holasss999 como estas 999freeze??? 999 :p999a999b999999c999d99aaaa999";
   char **elem;
   int num_elem;
   int i;
   
   elem = separar(linea, "999", &num_elem);
   for (i = 0; i < num_elem; i++)
      printf("elem[%2d] == \"%s\"\n", i, elem[i]);
   
   for (i = 0; i < num_elem; i++)
      free(elem[i]);
   free(elem);
   
   return EXIT_SUCCESS;
}

char **separar(char const *cad, char const *sep, int *num_elem)
{
   char **elem;
   char *p;
   int i;
   
   size_t nc_sep = strlen(sep);
   
   elem = malloc((strlen(cad) + nc_sep) / (nc_sep + 1) * sizeof *elem);
   
   for (i = 0; (p = strstr(cad, sep)) != NULL; cad = p + nc_sep){
      if (p != cad){
         elem[i] = malloc(p - cad + 1);
         sprintf(elem[i], "%.*s", p - cad, cad);
         i++;
      }
   }
   if (*cad != '\0'){
      elem[i] = malloc(strlen(cad) + 1);
      strcpy(elem[i], cad);
      i++;
   }
   *num_elem = i;
   
   return realloc(elem, i * sizeof *elem);
}


Un saludo
C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language