Extraña asignación en un array con -1

Iniciado por kutcher, 28 Julio 2014, 05:14 AM

0 Miembros y 2 Visitantes están viendo este tema.

kutcher

 Buenas, estoy tratando de implementar mi propia función strtok y buscando por la
red he encontrado un método bastante curioso el cual utiliza el numero negativo
-1 como indice en un array de caracteres para asignarle el carácter nulo

En consecuencia extrañamente obtienes el primer token en el puntero llamado
token, cosa que no entiendo como sucede aquí el código:

Código (cpp) [Seleccionar]
char *mystrtok(char *s, const char *delim)
{
   int c, sc = *delim;
   char *token = s;

   do{
       c = *s++;
       if (c == sc)
       {
           s[-1] = '\0';
           return (token);
       }
   }while (*s);

   return NULL;
}


Es la versión corta la modifique un poquito para exponer la parte que no entiendo

CalgaryCorpus

Genéricamente, la notacion que usa el parentesis cuadrado, como

p[ entero ]

es igual a

* ( p + entero )

por lo que

puntero[ -1 ]

es igual a

*( puntero - 1 )

El codigo que muestras mueve a "s" un lugar hacia adelante unas lineas antes por lo que si se quiere acceder a posiciones previas el -1 tiene (algo de) sentido.
Aqui mi perfil en LinkedIn, invitame un cafe aqui

eferion

c = *s++;

Es equivalente a:


c = *s;
s++;


Es decir, asigno a 'c' el valor apuntado por 's' y después hago que 's' apunte al siguiente carácter.


if (c == sc)
{
  s[-1] = '\0';
}


Si 'c' se corresponde con el delimitador, entonces tengo que eliminar ese delimitador... pero claro, el único puntero que tengo, 's', está apuntando al siguiente carácter... bueno, pues retrocedo una posición y listo.

kutcher

Cita de: CalgaryCorpus en 28 Julio 2014, 06:24 AM
por lo que

puntero[ -1 ]

es igual a

*( puntero - 1 )

Viéndolo de esa forma todo tiene mas sentido, solo una ultima consulta luego de esta asignación la cadena s queda modificada no?

rir3760

Cita de: kutcher en 28 Julio 2014, 16:23 PMluego de esta asignación la cadena s queda modificada no?
Si. El propósito de la función es buscar un único carácter y sustituirlo con un cero, si ello sucede se retorna el primer parámetro, caso contrario se retorna NULL.

A esa función se deberían realizar algunos cambios ya que si se busca un solo carácter no tiene caso que el segundo parámetro sea un puntero y ya que las variables "c" y "sc" (deberían ser de tipo char, no hay necesidad de declararlas con el tipo int) solo "pasan la cubeta" se pueden eliminar. Por ultimo no tiene en cuenta el caso donde el primer parámetro es una cadena nula.

Quedaría así:
char *mystrtok(char *s, char delim)
{
   char *p = s;
   
   do {
      if (*s == delim){
         *s = '\0';
         return p;
      }
   }while (*s++);
   
   return NULL;
}


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

kutcher

Cita de: rir3760 en 28 Julio 2014, 17:00 PM
Si. El propósito de la función es buscar un único carácter y sustituirlo con un cero, si ello sucede se retorna el primer parámetro, caso contrario se retorna NULL.

De ser así, porque al asignar la cadena s a una variable estática los caracteres posteriores al carácter nulo son asignados de igual manera a tal variable:

Código (cpp) [Seleccionar]
if (*s == delim){
  *s = '\0';
   *last = s; //<== Aqui luego de la supuesta modificación
  return p;
}


Blaster

#6
Cita de: kutcher en 28 Julio 2014, 17:51 PM
De ser así, porque al asignar la cadena s a una variable estática los caracteres posteriores al carácter nulo son asignados de igual manera a tal variable:

Como ya te han indicado el puntero s al encontrarse el primer carácter delimitador ya apunta al siguiente carácter a partir del cual realizas la correspondiente asignación hasta el siguiente carácter nulo.

rir3760

Cita de: kutcher en 28 Julio 2014, 17:51 PMDe ser así, porque al asignar la cadena s a una variable estática los caracteres posteriores al carácter nulo
En tu primer mensaje la función no tiene una variable con clase de almacenamiento estático, si actualizaste la función y te surge una duda por favor publica el código fuente completo.

Y si te interesa el tema de implementaciones propias de strtok puedes revisar varias de ellas en la discusión CRT personalizada.

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

kutcher

Cita de: rir3760 en 28 Julio 2014, 21:18 PM
por favor publica el código fuente completo.

Disculpa, este es el código original que he encontrado:

Código (cpp) [Seleccionar]
char *
strtok(char *s, const char *delim)
{
    static char *last;

    return strtok_r(s, delim, &last);
}

char *
strtok_r(char *s, const char *delim, char **last)
{
    char *spanp;
    int c, sc;
    char *tok;

    if (s == NULL && (s = *last) == NULL)
        return (NULL);

    tok = s;
    for (;;)
    {
        c = *s++;
        spanp = (char *)delim;
        do
        {
            if ((sc = *spanp++) == c)
            {
                if (c == 0)
                    s = NULL;
                else
                    s[-1] = 0;
                *last = s;
                return (tok);
            }
        }
        while (sc != 0);
    }
}


Creo que es la implementación de la función estándar strtok