¿Alguien puede ayudarme a entender este codigo de strstr?

Iniciado por mester, 22 Diciembre 2015, 13:55 PM

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

mester

Hola. Estaba haciendo una funcion para saber si hay una palabra dentro de una cadena, y luego ví que existe la función strstr();

int strstr(const char *str1, const char *str2) {
  char *cp = (char *) str1;
  char *s1, *s2;
  if (!*str2) return 0; //Que significa el (!*str2)
  while (*cp) {
    s1 = cp;
    s2 = (char *) str2;
    while (*s1 && *s2 && !(*s1 - *s2)) //Que significa (*s1 && *s2) y luego el && !(*s1 - *s2)
        s1++, s2++;
    if (!*s2) return 0;
    cp++;
  }
  return 1;
}


Devuelve 0 cuando ha encontrado una palabra y 1 si no.
Me gustaría saber que significado tiene '!' ante una función y ante un puntero. Y que obtienes al hacer *s1 && *s2, ¿los comparas?

Gracias.
Justicia es dar a cada uno lo que se merece

Stakewinner00


mester

Cita de: Stakewinner00 en 22 Diciembre 2015, 14:20 PM
https://es.wikibooks.org/wiki/Programaci%C3%B3n_en_C/Instrucciones_de_control

*x es el contenido apuntado por x, *str2 será el contenido apuntado por str2, etc

Si eso ya lo sé, pero no entiendo qué significa "(*s1 && *s2)" es decir, ¿es lo mismo que hacer (*s1 == *s2) o qué?
Justicia es dar a cada uno lo que se merece

class_OpenGL

#3
Respuesta corta: el operador '!' invierte entre true y false una expresión.
El operador && relaciona dos expresiones booleanas. Si alguna de las dos es false, entonces la expresión "expresion1 && expresion2" valdrá false, pero si las dos expresiones son true, entonces la expresión final será verdadera.

Respuesta larga:

Partimos de
Código (cpp) [Seleccionar]
*s1 && *s2 && !(*s1 - *s2)

Analicemos. El operador con menos prioridad en esa expresión es el &&, por lo que por ahora lo dejamos aparte y la dividimos en tres partes:
Código (cpp) [Seleccionar]
*s1 // Primera parte
*s2 // Segunda parte
!(*s1 - *s2) // Tercera parte


Vale, entonces, la única expresión que hay es !(*s1 - *s2). Dicha expresión tiene un paréntesis, el operador con más prioridad, por lo que lo evaluamos primero con el ejemplo donde *s1 vale 65, y *s2 vale 66. El paréntesis queda así:

Código (cpp) [Seleccionar]
65 - 66
Lo que a su vez equivale a...
Código (cpp) [Seleccionar]
-1 //Simplemente restamos

Entonces, ya tenemos el paréntesis. La expresión quedaría:
Código (cpp) [Seleccionar]
!(-1)

Lo que hace el operador '!' es cambiar de true a false o viceversa la expresión que tenga a la derecha. Por ejemplo, si tenemos "!(false)", pasaría a "true", y si tenemos "!(true)", pasaría a "false". Pero, ¿y que pasa cuando son números? Si tenemos un número distinto de cero, entonces pasa a ser 0 (por ejemplo, "!(2)" equivale a "0"), y si tiene un "0", entonces pasa a valer "1".

Sabiendo esto, la expresión de antes "!(-1)" quedaría así:
Código (cpp) [Seleccionar]
0 // Invertimos

Ya sabemos que la primera parte vale 65. Sabemos que la segunda parte vale 66 y sabemos que la tercera parte vale 0.  Entonces, nos quedaría así:

Código (cpp) [Seleccionar]
65 && 66 && 0

Las expresiones, normalmente, se evalúan de izquierda a derecha, por lo que primero evaluamos "65 && 66". Lo que hace el operador es lo siguiente:

Valor izquierdoValor derechoResultado
00false
0Distinto de 0false
Distinto de 00false
Distinto de 0Distinto de 0true

Entonces, la expresión ÚNICAMENTE valdrá true cuando los dos operandos sean DISTINTOS de 0. En cualquier otro caso, la expresión será false.

Entonces, "65 && 66" pasaría a valer true.

Ahora tenemos la expresión "true && 0". Como ya hemos visto, como hay un operando que vale 0, entonces la expresión es false.

Sé que es largo de leer, pero creo que si se lee con detenimiento, se puede entender perfectamente

______________________________________

PD.: Hubiera sido mejor la expresión
Código (cpp) [Seleccionar]
*s1 && *s2 && *s1 == *s2

Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL

MAFUS

#4
Muy buenas.

En línea 4:
if (!*str2) return 0;
*str2 se puede traducir a str[0]: valor del primer carácter de la cadena str2.
La exclamación que tiene delante niega lógicamente dicho valor. El valor 0 es el único valor que negado hace que un if ejecute las instrucciones asociadas. Por otra parte un valor 0 en una cadena es el carácter nulo ( '\0' ) de fin de cadena que espera C como marcador de fin de cadena.
Todo ello quiere decir que si str2 es una cadena vacía, sólo compuesta por el carácter de fin de cadena ( "\0" ), el la función retornará 0.
La línea 10 hace lo propio con s2.

En la línea 8:
while (*s1 && *s2 && !(*s1 - *s2))
while ejecuta su código asociado siempre que lo que tenga entre paréntesis sea diferente a 0, la forma en C de decir que una expresión es cierta.
El operador AND lógico ( && ) solo le interesa que sus operandos sean 0 o distinto a 0. *s1 y *s2 son un carácter que, para AND, mientras sean distintos a 0, o como ya hemos visto el carácter de fin de cadena, será cierto.
Donde dice !(*s1 - *s2) se restan dos caracteres. Para C lo que se está es restando los valores numéricos que representan esos caracteres (ASCII), si *s1 y *s2 son iguales el resultado aritmético es 0. Y aquí entra a jugar el operador de negación ( ! ): si resulta que son iguales, valor 0 -> falso, se niega y se convierte en verdadero, con lo que para el conjunto de la instrucción hará que while ejecute sus instrucciones asociadas.
Esto quiere decir que: mientras los caracteres de s1 y s2 no sean el carácter nulo y ambos sean iguales while ejecutará sus instrucciones asociadas.

Aunque la función que has dado es rara, porqué sólo indica que ha hay coincidencia o no. La función de librería estándar devuelve el puntero a la primera ocurrencia en str1 de la cadena apuntada por str2 o un puntero NULL en caso de no haber coincidencias.

mester

Gracias class_OpenGL y MAFUS. Poco a poco lo estoy entendiendo. Es que me cuesta, hay que tener en cuenta que no he hecho una carrera ni nada de informática, aún estoy en Bachillerato jeje.
Entonces si escribo

while((*s1 && *s2) == (*s1 == *s2))


Es decir, según lo explicado. ¿(*s1 && *s2) deberá devolver 1 o true si no son '\0', y (*s1 == *s2) deberá devolver 1 o ture si son iguales y 0 si son diferentes?
Justicia es dar a cada uno lo que se merece

MAFUS

#6
 ;-) Sí, así es  ;-)

Yo tampoco he hecho informática. Soy un autodidáctico de la vida  ;D

Una cosa: aunque tu expresión del while es correcta, para el ordenador, para nos debería reflejarse como

while(*s1 && *s2 && (*s1 == *s2))

Recuerda que lo que quieres decir al compilador y a la gente que ve el código es:
while((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))