[ANSI C] Split(), strlen(), mid(), Instr(), strcpy().

Iniciado por BlackZeroX, 12 Enero 2011, 22:55 PM

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

BlackZeroX

.
Esta es la version de split() ya esta corregida debugeada y sirve en todo caso.

Quien no sepa usar Vectores en C esta muerto ( ** ), es decir Puntero a Puntero.

Corregido por segunda vez:



#include<stdlib.h>
#include<stdio.h>

#ifndef bool
typedef enum bool { false, true } bool;
#endif

unsigned int rectific_num(unsigned int vval,unsigned int vmin,unsigned int vmax);
bool fix_numbers_range(unsigned int* vIndexIni,unsigned int* vIndexEnd, unsigned int* vLen, unsigned int vMin, unsigned int vMax);
unsigned long strlen(char* string);
unsigned long instr(unsigned long start,char* string1,char* string2);
char* mid(char* str, unsigned int start, unsigned int len);
char* strcpy(char* str_dest,char* str_src);
char** split(char* str, char* delimiter, long* limit);

int main()
{

   long lim=-1;
   long i=0;
   char **array = split((char*)".Este.es.Hola.Mundo.Hola.mundo.",(char*)".",&lim);

   if ( array != 0 )
   {
       printf("Index\tValue\n",lim);
       for ( i=0 ; i <= lim ;i++ )
       {
           printf("%d\t%s\n",i,array[i]);
           free (array[i]);
       }
       free(array);
   }
   getchar();
   return 0;
}

unsigned int rectific_num(unsigned int vval,unsigned int vmin,unsigned int vmax)
/**
   Corrige [vVal] con respecto a un minimo y a un maximo valor.
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   if (vval < vmin)
       return vmin;
   else if ( vval > vmax )
       return vmax;
   else
       return vval;
}

bool fix_numbers_range(unsigned int* vIndexIni,unsigned int* vIndexEnd, unsigned int* vLen, unsigned int vMin, unsigned int vMax)
/**
   Corrige los rangos de [vIndexIni],[vIndexEnd], [vLen] con respecto a un minimo y a un maximo valor.
   [vLen] corresponde a la distancia entre [vIndexIni] y [vIndexEnd].
   Se retorna false solo si [vMax] es menor que que [vIndexIni] o que [*vLen] es igual o menor a [0]
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   if ( vMax >= *vIndexIni && *vLen != 0 )
   {
       *vIndexIni = rectific_num(*vIndexIni,vMin,vMax);
       *vIndexEnd = rectific_num(*vIndexIni + *vLen,*vIndexIni,vMax);
       *vLen= *vIndexEnd - *vIndexIni+1;
       return ( (*vLen > 0) ? true: false);
   } else {
       return false;
   }
}

unsigned long strlen(char* string)
/**
   Retorna la longitud de [string]
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   unsigned long i=0;
   while (*(string++)) i++;
   return i;
}

char* strcpy(char* str_dest,char* str_src)
/**
   Copia [*str_src] a [*str_dest].
   Retorna el puntero a [str_dest]
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   char *copyreturn = str_dest;
   while(*(str_dest++)=*(str_src++));
   return copyreturn;
}

unsigned long instr(unsigned long start,char* string1,char* string2)
/**
   [Start] indica la posicion inicial donde se empesara a buscar en [string1]
   Retorna la posicion de [*string2] en [*string1].
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   unsigned long  q,c,limit;
   q=c=limit=0;
   long ls2len=0;

   ls2len = strlen(string2) - 1;

   if ( ls2len >= 0 )
   {
       limit = strlen(string1)-ls2len;

       if ( limit > 1 )
       {
           q = start-1;
           while ( q < limit )
           {
               while ( string1[q+c] == string2[c] )
                   if ( (c++) == (unsigned long)ls2len )
                       return q+1;
               q+=c+1;
               c=0;
           }
       }
   } else if (*string1 > '\0') {
       return 1;
   }
   return 0;
}
char* mid(char* str, unsigned int start, unsigned int len)
/**
   Se obtiene el fragmento deseado de [*str]
   [Start] Indica desde donde se empesara
   [Len] Indica la distancia.
   Retorna el puntero al clon del fragmento deseado de [*str]
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   char* pch_t = 0;
   unsigned int ul_str=strlen(str);
   unsigned int ul_end=start+len;
   start--;
   if ( fix_numbers_range(&start,&ul_end,&len,0,ul_str) == true )
   {
       if ( (pch_t = (char*)malloc(sizeof(char)*len)) != 0 )
       {
           for (ul_str=0;ul_str < (len-1) ;start++,ul_str++ )
               pch_t[ul_str] = str[start];
           pch_t[len-1]='\0';
       }
   } else {
       if ( (pch_t = (char*)malloc(sizeof(char))) != 0 )
           pch_t[0]='\0';
   }
   return pch_t;
}

char** split(char* str, char* delimiter, long* limit)
/**
   Separa a [*str] cada vez que se encuentre a [*delimiter] con un limite definido en [*limit]
   Si [*limit] = -1 se crea un Maximo mayor a [-1] en el indice del vector retornado
   Si [*limit] > -1 Se indica y establece un indice mayor [pero no fijo] del indice mayor del vector retornado
   En ambos casos [*limit] retorna el Indice maximo del vector retornado por la funcion y la funcion retorna el puntero a el vector retultante.
   En casos contrarios no crea un vector y retorna 0 y [*limit] = [-1]
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
   unsigned int ui_lp  =1;
   unsigned int ui_inc =1;
   unsigned int ui_lns =0;
   unsigned int ui_del =0;
   unsigned long ui_ub =0;
   char **pi_out       =0;

   if ( *limit >= -1 )
   {
       if ( strlen(delimiter) == 0 )
           delimiter = (char*)" ";
       ui_lns = strlen(str);
       ui_del = strlen(delimiter);
       pi_out = (char**)malloc(sizeof(char*));
       for(;pi_out!=0;)
       {
           if ( ui_ub == *limit )
           {
               pi_out[ui_ub] = mid(str, ui_lp,ui_lns);
               ui_ub = *limit;
               break;
           }
           ui_inc = instr(ui_inc, str, delimiter);
           if ( ui_inc == 0 )
           {
               pi_out[ui_ub] = mid(str, ui_lp,ui_lns);
               break;
           }
           pi_out[ui_ub] = mid(str, ui_lp, ui_inc - ui_lp);
           pi_out = (char**)realloc(pi_out,sizeof(char*)*(++ui_ub+1));
           ui_lp = ui_inc + ui_del;
           ui_inc = ui_lp;
       }
       *limit = ui_ub;
       return pi_out;
   }
   *limit=-1;
   return 0;
}



Nota.: Si alguien ve algun fallo por favor de no golpearme gracias!¡.

Temibles Lunas!¡.
The Dark Shadow is my passion.

Littlehorse

El propósito de los comentarios es aclarar el código y no lo contrario. Si quieres poner créditos los puedes agregar al principio, pero poner spam en los comienzos de cada función sinceramente invitan a no seguir leyendo el código.

Por otro lado, el tipo de dato bool no existe en C, solo en C++, y viendo que estas utilizando las cabeceras de C, deberías definir el tipo de dato bool por tu cuenta. No he leido el resto del código; utilizar typedefs ayuda a que el código sea mas comprensible a primera vista.

Saludos



An expert is a man who has made all the mistakes which can be made, in a very narrow field.

leogtz

#2
Siempre retornas 1 en el main() eso es incorrecto, para el sistema operativo tu programa no funciona bien.

unsigned long strlen(char* string)
{
    unsigned long i=0;
    while (*string++)
    i++;
    return i;
}
Código (perl) [Seleccionar]

(( 1 / 0 )) &> /dev/null || {
echo -e "stderrrrrrrrrrrrrrrrrrr";
}

http://leonardogtzr.wordpress.com/
leogutierrezramirez@gmail.com

BlackZeroX

#3
.
Les agradezco sus comentarios pero acabo de ver un error, y ahorita solo me intriga que me salte este error.

Código (c,16) [Seleccionar]


int main()
{

    long lim=-1;
    long limback=lim;
    char **array = split((char*)"Este es un hola mundo desde InfrAngeluX-Soft",(char*)"u",&lim);

    if ( array != 0 )
    {
        limback=lim;
        for (; lim>-1 ;lim-- )
            printf ("%d \t %s \n", lim, array[lim] );

        for (; limback>0 ;limback-- )
            free (array[limback]);
        free(array);
    }
    getchar();
    return 0;
}




Heap block at 003E1750 modified at 003E175E past requested size of 6


Nota: seguire viendo por que me salta...

Dulces Lunas!¡.
The Dark Shadow is my passion.

Psyke1

Hola Black! :D
Parece que te estás pasando ya a Cpp eh? ;)

Me gusta tu función Instr(), me recuerda a la que hice yo hace días en vb6 :silbar: :
unsigned long instr(unsigned long start,char* string1,char* string2)
/*
   [Start] indica la posicion inicial donde se empesara a buscar en [string1]
   Retorna la posicion de [*string2] en [*string1].
   By BlackZeroX ( http://Infrangelux.sytes.net/ )
*/
{
   unsigned long  q,c,limit;
   q=c=limit=0;
   long ls2len=0;

   ls2len = strlen(string2) - 1;

   if ( ls2len >= 0 )
   {
       limit = strlen(string1)-ls2len;

       if ( limit > 1 )
       {
           q = start-1;
           while ( q < limit )
           {
               while ( string1[q+c] == string2[c] )
                   if ( (c++) == (unsigned long)ls2len )
                       return q+1;
               q+=c+1;
               c=0;
           }
       }
   } else if (*string1 > '\0') {
       return 1;
   }
   return 0;
}


Código (vb) [Seleccionar]
Option Explicit
Option Base 0

Private Function myInstr&(ByVal Start&, ByVal String1$, ByVal String2$)
Dim bvString1() As Byte, bvString2() As Byte
Dim ls2Len&, lLimit&
Dim Q&, C&
   ls2Len& = ((Len(String2$)) - &H1)
   If ls2Len& > -1 Then
       lLimit& = ((Len(String1$)) - ls2Len&)
       If lLimit& > 1 Then
           bvString1 = (VBA.StrConv(String1$, vbFromUnicode))
           bvString2 = (VBA.StrConv(String2$, vbFromUnicode))
           Q& = (Start& - &H1)
           Do While (Q& < lLimit&)
               Do While (bvString1(Q& + C&) = bvString2(C&))
                   'Debug.Print ChrW$(bvString1(Q& + C&)); ChrW$(bvString2(C&))
                   C& = C& + &H1
                   If ((C& - &H1) = ls2Len&) Then
                       myInstr& = Q& + &H1
                       Exit Function
                   End If
               Loop
               Q& = (Q& + C&) + &H1
               C& = &H0
           Loop
       End If
   End If
End Function

http://goo.gl/Pv2Be

:xD
Un día de estos que no estés ocupado te tengo que preguntar dudas por msn... :P

DoEvents! :P

BlackZeroX

#5
.
Ya corregi el error el problema era con la funcion mid(), TODO ya funciona como deberia de ser.

@ Leo Gutiérrez.
Puse la comparacion con el caracter nulo solo para tener la menor cantidad de advertencias de mi IDE/Compilador.

P.D.: Si Rana es el mismo solo que lo tube que traducir, fue la que mas me gusto.

Dulces Lunas!¡.
The Dark Shadow is my passion.

08l00D

Cita de: Littlehorse en 12 Enero 2011, 23:44 PM
Por otro lado, el tipo de dato bool no existe en C, solo en C++
Saludos

En realidad si existe en C.. se implemento a partir del estandar C99..
se puede utilizar como _Bool ... o bool (incluyendo <stdbool>, donde esta definido)
aunque igual siempre es mejor definirlo para no joder la compatibilidad con compiladores viejos..


unsigned long strlen(char* string)
/**
    Retorna la longitud de [string]
    By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{//no esta mal pero deberias restarle 1 a i antes de retornarla asi no incluye el valor te terminador de cadena, asi el que use tu implementacion de la funcion no tenga que restarle 1 al valor cada vez que la use...
    unsigned long i=0;
    while (*(string++) != '\0') i++;
    return i;
}

char* strcpy(char* str_dest,char* str_src)
/**
    Copia una string a otra [*str_src] a [*str_dest].
    Retorna el puntero a [str_dest]
    By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{
    while( (*(str_dest++)=*(str_src++) == '\0' ) ); // MAL... la comparacion esta mal .. tenes que comparar si la cadena es distinta a '\0' no igual.... cuando copias tambien esta mal ... ya que estarias copiando el resutado de la comparacion ..la precedencia del operador == es mayor al de asignacion... necesitas parentesis..
    return (str_dest);
}



Por lo demas no lo vi en detalle ... pero vi que los punteros devueltos por malloc los comparas por 0 .. lo cual en teoria no esta mal ya que el compilador se da cuenta que el 0 esta siendo utilizada en un contexto de puntero y hace la conversion a NULL implicitamente.. pero no es una buena practica en C... utiliza siempre NULL.. al igual que cuando inicialices tus punteros...
ah y otra cosa cuando tenes una expresion como *cadena++  los parentesis no son necesarios ... el operador ++ tiene mayor precedencia que el de desreferencia...

Saludos

Littlehorse

#7
CitarEn realidad si existe en C
No, en C++ bool es un tipo de dato primitivo aparte. En C, desde C99 como bien decís, se define mediante macros en stdbool.h, pero es al día de hoy que se sigue definiendo aparte no solo por retrocompatibilidad, también por claridad de código.

Citar
pero no es una buena practica en C... utiliza siempre NULL.. al igual que cuando inicialices tus punteros...

No esta establecido que sea una mala practica no utilizar NULL. Es simplemente una cuestión de estilo que se suele aplicar mas que nada en código critico donde se requiera dejar bien en claro que se esta tratando con punteros, pero no mas que eso.

Citaran integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.


Personalmente me molesta bastante leer NULL por todos lados cuando esta mas que claro que se trata de punteros. Si se necesita dejar en claro que es un puntero no me parece mal, pero tampoco exagerar.
En C++ directamente es lo contrario, el mismo creador recomienda utilizar 0 en lugar de NULL.


Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

BlackZeroX

#8
Cita de: 08l00D en 13 Enero 2011, 15:49 PM


unsigned long strlen(char* string)
/**
    Retorna la longitud de [string]
    By BlackZeroX ( http://Infrangelux.sytes.net/ )
**/
{//no esta mal pero deberias restarle 1 a i antes de retornarla asi no incluye el valor te terminador de cadena, asi el que use tu implementacion de la funcion no tenga que restarle 1 al valor cada vez que la use...
    unsigned long i=0;
    while (*(string++) != '\0') i++;
    return i;
}




Muchas gracias por "tu corrección", pero por otro lado la funcion y objetivo es colo contar caracteres sin el char NULL por ende esta correcto



printf("%d\n",strlen((char*)"hola"));
/*
    tiene que devolver una longitud de 4 caracteres que es lo que interesa, el '\0' al final no nos interesa.
    * Salida 4.
*/



En strcpy() gracias me hiciste ver un error de hecho, y de hecho ni hiba a poner la igualdad a '\0' ( ya que se obvia ) pero como dije arriba solo puse dichas comparaciones para evitar la mayor cantidad de Advertencias que me tiraba mi IDE/Compilador. aun que me tira una de unsigned long y un long ( esta la he estado ignorando ) ya que como se que un long abarca un buen numero..., y por otro lado ya se como se evaluan los operadores unitarios.

Gracias por lo de NULL, solo una duda mas si pongo (char*)0 tambien vale?, en mi forma de pensar es correcto pero desearia ver que piensan otros ya que no me deseo encerrar! en una conjetura¡.

P.D.: El objetivo de estos codigos para mi es mejorar la comprension, sintaxis ( a tal grado de que ya no use tanto la web tal y como lo hago ya con vb6 q ya puedo hacer codigo de forma fluida usando las APIS del sistema. ), y evitar horrores de sintasys y demás cosas, ¿no voy tan perdido vdd? xP.

Dulces Lunas!¡.
.
The Dark Shadow is my passion.

Littlehorse

CitarGracias por lo de NULL, solo una duda mas si pongo (char*)0 tambien vale?, en mi forma de pensar es correcto pero desearia ver que piensan otros ya que no me deseo encerrar! en una conjetura¡.
Dependiendo del caso legal es, pero correcto no. Utiliza NULL en casos donde sea importante que el programador detecte a primera vista que se esta tratando de un puntero, para los otros casos puedes usar 0 perfectamente.
En el caso de C++, con 0 basta y sobra.

#ifndef NULL
#ifdef _cpp
#define NULL 0
#else /* not cpp */
#define NULL ((void *)0)
#endif
#endif



Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.