Warning: Son las 3 de la mañana [y todo el mundo bailando].
1) Tu código decía:
verificar (NODO *H , float tole) {
while (H->next) {
while (H) {
if(((((H->info).v_medido)*100)/((H->info).v_nominal))!= tole) {
printf("Codigo de la Resistencia: %s\n",(H->info).codigo);
printf("Valor nominal de la Resistencia: %d\n",(H->info).v_nominal);
printf("Valor Medido de la Resistencia: %g\n",(H->info).v_medido);
}
H = H -> next;
}
}
}
El H = H -> next; está **DENTRO** del while(H). Osea que, si H == null, no avanza el cursor (cosa que está *muy* bien, porque si H es NULL querer hacer H -> next; va a fallar estrepitósamente). El problema es que, como el while(H) no se cumple, va a intentar ejecutar la instrucción siguente al while(), pero *fuera de él*. Como no hay ninguna instrucción fuera, ejecuta el "vuelta al principio del while" del while de afuera (el while H->next). Y ahí lo mismo que decía recién: H va a ser NULL (sino, seguiría en el while de adentro), y H->next va a dar segmentation fault.
Eso siendo "técnico". Si lo encarás "conceptual", ¿por qué hay dos condiciones distintas que cumplir para recorrer una lista? ¿Acaso "recorrer una lista" no es hacer algo "mientras siga teniendo algún elemento en la lista"? Buen, eso es lo que hice: while(elemento != NULL). Si eso se cumple, hago lo que carajo quiera hacer con ese elemento actual que tengo, y por último avanzo el cursor (para no quedarme eternamente dandole masa al mismo elemento).
Y ahí es donde te digo que "while(elemento != NULL)" es más expresivo que "while(H)". Se podría mejorar el nombre "elemento" que es re genérico, pero... ¿qué carajo es "H"?
2) El enunciado que vos pusiste dice:
Cita:Una vez finalizada la carga se debera listar en pantalla todas las resistencias cuyo valor medido difiera de su valor nominal por mas de un porcentaje que ingresaremos al comienzo del programa por linea de comando (arg del main)
Me quedo con esas dos cosas resaltadas: difiera implica restar y quedarse el valor absoluto, porque es onda "una distancia" (ok, podría interesarnos con signo la diferencia, para saber si está por arriba o abajo, pero vamos con el punto que sigue). "por más de" habla de eso: que la diferencia esa sea mayor a la tolerancia. ¿Cuál es la idea? Si tengo una resistencia que debería ser de, no se, 100, y la pruebo y es de 150, y la tolerancia es el 10%, buen, claramente la resistencia está como el culo, y por eso quiero que "salte la ficha". ¿Y cómo sabemos eso? Bueno, porque 150 - 100 = 50 omhs es la diferencia de resistencias. Y en una resistencia de 100 nominales y tolerancia del 10% significa que me puedo desviar 10 omhs. Osea, las resistencias entre 90 (100 - 10) y 110 (100 + 10) ohms van a estar OK, el resto tengo que marcarlas como malas.
Y ahora que leo, hay dos errores: la tolerancia debería multiplicarse por el valor nominal (no quiero comparar contra un 10% sino contra una cantidad de ohms, que es lo que me da la resta de valores), y el signo es >, no < (quiero aquellas cuya diferencia sea MAYOR a la permitida, no menor).
Entonces esa línea sería:
if(valorAbsoluto(resistencia->v_medido - resistencia->v_nominal) > tolerancia * resistencia->v_nominal) { // va -> porque ahora tengo el puntero
3) DATOS *resistencia = &(elemento->info);
Antes del signo =, declaro una variable llamada resistencia, de tipo DATOS *. Cualquier_tipo * es una declaración de "puntero a Cualquier_tipo". Así como tu campo next del struct nodo es un puntero a struct nodo (pusiste "struct nodo *next"), esta variable resistencia es un puntero a una cosa de tipo DATOS (tu struct que tiene codigo, v_nominal y v_medido).
El = es el operador de asignación.
en lo que está a la izquierda del = guardo el resultado de evaluar lo que está a la otra izquierda del mismo.
En este caso, lo que está a la derecha es el operador & aplicado al campo info del elemento. & es el operador que devuelve
un puntero a lo que sea que le pasemos por parámetro (o, más técnicamente, devuelve
la dirección de memoria de lo que tiene como parámetro).
Entonces, a un poquito más alto nivel,
declaramos una variable resistencia que apunte al campo info del elemento. Entonces, en vez de volverme boludo escribiendo elemento->info muchas veces, puedo usar directamente "resistencia".
Podría haber hecho también esto:
DATOS resistencia = elemento->info;
Pero ahí estaría diciendo que resistencia *es* un struct con los 3 campos, y al asignarle el info de elemento estaría copiando **todo el struct** a un nuevo struct creado en memoria. Entonces, por un lado desperdicio memoria y hago más lento el asunto (tiene que copiar varios campos). La diferencia es mínima, sí, pero es choto. Pero, por otro, estoy generando UNA COPIA, por lo que si llegara a modificar algo de resistencia, el elemento original no se vería afectado.
¿Esto último es necesariamente malo? No. Podría interesarme hacer eso en algún contexto, y en algún otro podría interesarme que eso no pase. En casos como este, en que no modificamos esos datos, no nos calienta en absoluto si se copia o no. Cualquiera de los dos casos funcionaría igual, salvando ese temita de performance que no vamos a notar. Pero sí está bueno tener en cuenta que en otros casos puede hacer diferencia.
Si no fui claro en algo o quedó algo en el tintero, chifle nomái.
Abrazo!