Autor
|
Tema: Dudas con cola e INT_MAX lenguaje C. (Leído 5,850 veces)
|
NOB2014
Desconectado
Mensajes: 366
|
Hola, gente, que tengan un muy buen día. - Tengo claro que deberíamos pedir ayuda cuando el programa falla y este no es el caso (por lo menos es lo que parece) pero estoy tratando de hacer esto solo y como la mayoría sabe no tengo a quien consultar que no sean Uds. los molesto. - Mi duda está desde la línea 78 a la 96, ¿es todo correcto lo que se encuentra dentro de esas líneas? y otra cosita, como puedo hacer para liberar la memoria de Elem y elem (lineas 78 y 88). Me falta la función quitar que intentare luego de vuestra(s) opinión(es) .- Estoy aprendiendo, por lo tanto, cualquier sugerencia de cambios en el código será bienvenida por dura que sea. - #include <stdio.h> #include <stdlib.h> #include <limits.h> typedef struct ElementoLista{ int dato; int elementos; struct ElementoLista *siguiente; }Elemento; Elemento *inicio = NULL; Elemento *fin = NULL; void menu( void ); void limpiar( void ); Elemento *agregar( Elemento *E ); void mostrar( Elemento *E ); int main( void ){ menu(); return 0; } void menu( void ){ int opc, ok, ch; Elemento *elemento = NULL; do{ do{ limpiar( ); printf( "\n =============== Menu principal ===============\n" "\n 1 - Agregar a la cola" "\n 2 - Quitar de la cola" "\n 3 - Listar cola" "\n 4 - Salir\n" "\n ingrese opcion.....:" ); ok = scanf( "%d", &opc ) == 1 && opc > 0 && opc <= 4; while ((ch = getchar()) != EOF && ch != '\n'); }while( !ok ); switch ( opc ){ case 1: elemento = agregar( elemento ); break; case 2: //cola = quitar( elemento ); break; case 3: mostrar( elemento ); break; case 4: break; } }while( opc != 4 ); } void limpiar( void ){ } Elemento *agregar( Elemento *E ){ int ok, ch, dto; do{ limpiar(); printf( "\n Ingrese dato (mayor a 0 y menor a %d)....: ", INT_MAX ); ok = scanf( "%d", &dto ) == 1 && dto >0 && dto <= INT_MAX ; while ((ch = getchar()) != EOF && ch != '\n'); }while( !ok ); if( E != NULL ){ Elemento *Elem = calloc( sizeof( Elemento ), 1 ); Elem->dato = dto; Elem->siguiente = NULL; fin = Elem; Elem->elementos += 1; E->siguiente = Elem; return Elem; }else{ Elemento *elem = calloc( sizeof( Elemento ), 1 ); elem->dato = dto; elem->siguiente = NULL; inicio = elem; fin = elem; elem->elementos = 1; return elem; } return E; } void mostrar( Elemento *E ){ Elemento *auxiliar; if( E != NULL ){ auxiliar = inicio; while( auxiliar != NULL ){ printf( "\n %d", auxiliar ->dato ); auxiliar = auxiliar->siguiente; } }else{ } printf( "\n\n Pulse una tecla para continuar..." ); }
Saludos.
|
|
« Última modificación: 22 Agosto 2016, 02:56 am por NOB2014 »
|
En línea
|
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
|
|
|
class_OpenGL
Desconectado
Mensajes: 437
Si usas Direct3D, no eres mi amigo :P
|
A ver, si, técnicamente yo lo veo bien, pero en mi opinión, está mal estructurado. Lo que yo haría es la siguiente estructura: typedef struct ElementoLista{ int dato; struct ElementoLista *siguiente; } Elemento; typedef struct { Elemento *ultimo; unsigned int num_elementos; } Pila; typedef struct { Elemento *primero; unsigned int num_elementos; } Cola; // Si se retorna 0 por alguna de las dos funciones siguientes, ha habido error. De lo contrario, todo ha ido correctamente int agregar_a_pila(pila *pila); int agregar_a_cola(cola *cola); int quitar_a_pila(pila *pila); int quitar_a_cola(cola *cola); void mostrar_pila(const pila *pila); void mostrar_cola(const cola *cola);
Pequeño detalle a tener en cuenta: ok = scanf( "%d", &dto ) == 1 && dto >0 && dto <= INT_MAX ;
Un entero JAMÁS va a ser mayor que INT_MAX (si eso sucediera, sería un bug del compilador), así que es una tontería poner la condición 'dto <= INT_MAX'
|
|
|
En línea
|
| Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL |
|
|
|
|
AlbertoBSD
Programador y
Moderador Global
Desconectado
Mensajes: 3.705
🏴 Libertad!!!!!
|
Se ven bien las líneas que comentas solo un detalle con la variable elementos. y sobre liberarlos no es necesario en esa funcion ya que si se vuelven parte de la cola, solo sera necesario liberarlos cuando los quieras eliminar.
El detalle con los elementos es que cada elemento tiene su propio contador de elementos y eso no deberia de ser asi, solo necesitas un contador de elementos y no deberia de ser parte de la esteucutura individual de cada elemento.
Saludos
|
|
« Última modificación: 21 Agosto 2016, 22:09 pm por AlbertoBSD »
|
En línea
|
|
|
|
NOB2014
Desconectado
Mensajes: 366
|
Hola, gracias a ambos por responder. - class_OpenGL voy a estudiar tu código. - Un entero JAMÁS va a ser mayor que INT_MAX (si eso sucediera, sería un bug del compilador), así que es una tontería poner la condición 'dto <= INT_MAX'
No estoy de acuerdo, si se ingresa un dato mayor a INT_MAX no se sale del bucle, en cambio, si no pongo esta condición el compilador lo transforma a un número negativo o algo por el estilo, no recuerdo. Saludos.
|
|
|
En línea
|
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
|
|
|
NOB2014
Desconectado
Mensajes: 366
|
El detalle con los elementos es que cada elemento tiene su propio contador de elementos y eso no deberia de ser asi, solo necesitas un contador de elementos y no deberia de ser parte de la esteucutura individual de cada elemento. Si amigo, un graso error él mío, ya lo solucione. -
|
|
|
En línea
|
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
|
|
|
class_OpenGL
Desconectado
Mensajes: 437
Si usas Direct3D, no eres mi amigo :P
|
No estoy de acuerdo, si se ingresa un dato mayor a INT_MAX no se sale del bucle, en cambio, si no pongo esta condición el compilador lo transforma a un número negativo o algo por el estilo, no recuerdo. Lo que digo es 100% verdad, y te lo demuestro. Un entero, en informática, se almacena en binario con una cierta cantidad de bits. En C, con ordenadores actuales, se suelen almacenar con 32 bits. Entonces, dado que hay un espacio limitado en la que poder almacenar el entero, es imposible pasar ese límite, porque el tamaño de un entero en C es fijo. Entonces, ¿por qué no sale del bucle? Imaginemos que introduces el valor INT_MAX + 1. ¿Qué es lo que va a pasar? Que scanf va a transformar lo introducido a binario, por lo que obtendremos lo siguiente: 1000000000000000000000000000000 Aquí hay un 1 y 31 0s. Eso, interpretado para un entero con signo, da como resultado un número negativo, por lo que 'ok' valdrá 0 (ya que no se cumple que sea mayor que 0). Entonces, el while se ejecuta de nuevo, y por lo tanto, te pide otro número, entonces por eso parece que si introduces un número superior a INT_MAX, entonces el bucle se repite hasta que introduzcas otro número. A modo de experimento, mira qué pasa si introduces el 4294967298, un número claramente superior a INT_MAX
|
|
|
En línea
|
| Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL |
|
|
|
|
NOB2014
Desconectado
Mensajes: 366
|
estoy desconcertado con esto, yo había intentado unas cuantas veces y siempre seguía en el bucle si el ingreso era mayor que el permitido por INT_MAX, ahora resulta que en ciertos casos también me falla y pone un número distinto al ingresado y sale del bucle, debo suponer que esto no tiene solución, soy muy exigente con las validaciones de ingreso de datos. -
|
|
|
En línea
|
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
|
|
|
AlbertoBSD
Programador y
Moderador Global
Desconectado
Mensajes: 3.705
🏴 Libertad!!!!!
|
Si se quiere validar bien ciertos inputs se puede hacer con:
fgets strtol
asi limitas el input a ciertos limite de entrada. Y con el strtol validas si el input tiene caracteres no validos.
Saludos!
|
|
|
En línea
|
|
|
|
class_OpenGL
Desconectado
Mensajes: 437
Si usas Direct3D, no eres mi amigo :P
|
ATENCIÓN, RESPUESTA LARGAPrimero, para que entiendas mejor, voy a explicar algo necesario. Para entender lo que voy a explicar, tendrás que dominar un poco la base binaria y cómo pasar entre decimal y binario. Procedo a explicar cómo se puede almacenar un entero con signo Imaginemos que queremos guardar el número -123 como un entero sin signo. Para hacerlo lo que tenemos que hacer es restar a 2^31 - 1 (2 elevado a 31 menos 1) con 123 (he puesto 31 porque un entero suele ocupar 32 bits, y hay que restar 1 porque el último bit se usa para "saber si el número es positivo o negativo"). El resultado de esa operación es 2147483524. Ahora convertimos ese número a binario: 1111111111111111111111110000100 Aquí hay 31 bits. Por último, tenemos que poner el último bit como 1, para indicar que el número es negativo (lo ponemos a la derecha): 11111111111111111111111110000100 CONCLUSIONES IMPORTANTES DE ESTE PROCESO: - Si el último bit vale 1, entonces seguro que el número es negativo, de lo contrario, el número es positivo
(En realidad, la CPU hace otro proceso más simple, pero que es un poco más difícil de ver a simple vista, por eso lo expliqué así). _____________________________________________________________________ Una vez sabido esto, procedamos a explicar tu duda: estoy desconcertado con esto, yo había intentado unas cuantas veces y siempre seguía en el bucle si el ingreso era mayor que el permitido por INT_MAX, ahora resulta que en ciertos casos también me falla y pone un número distinto al ingresado y sale del bucle, debo suponer que esto no tiene solución, soy muy exigente con las validaciones de ingreso de datos. -
Vamos a enumerar lo que hace la función scanf: scanf lee el entero, y lo convierte a binario hasta que se acaben los dígitos introducidos. Una vez obtenido el número, guarda los primeros 32 bits en la variable. Ahora imagina que has introducido 2147483650 (que es INT_MAX + 1). Vamos a convertir ese número a binario: 10000000000000000000000000000001 Aquí, scanf ya tiene directamente los 32 bits, por lo que los copia sin fijarse en la variable y dice que todo ha ido bien. Entonces, una vez que la variable tiene esos bits, vamos a convertir ese número binario a entero con signo. - Primero, el bit número 32 es 1, por lo que el número va a ser negativo.
- Segundo, teniendo en cuenta lo que expliqué al principio de esta respuesta, convertimos los 31 primeros bits a decimal. Resultado: 1.
- Tercero, realizamos la operación inversa a lo del principio de la respuesta: 2^31 - 1 - valor = 1. Despejamos la ecuación... valor = 2^31 - 2 = 2147483646
Por lo tanto, si por la consola introducimos INT_MAX + 1, lo que en realidad almacenaremos en la variable entera con signo es -2147483646. ____________ Ahora bien, ¿por qué a veces si que da como resultado un número positivo? Eso es sencillo, lo que pasa es que el número resultante tenía como último bit un 0, por lo que como ya hemos dicho, eso significa que la variable será positiva. EJEMPLO RÁPIDO: Introducimos por consola 4294967336 (mayor a INT_MAX) Este número en binario es 100000000000000000000000000101000 Copiamos los 32 primeros bits a la variable: 00000000000000000000000000101000 El bit número 32 de la variable vale 0 (puedes contarlo tu mismo). Como el bit nº 32 vale 0, entonces la variable será positiva, pero valdrá 40 (esto lo sacas de convertir 00000000000000000000000000101000 a binario).
|
|
|
En línea
|
| Programador aficionado. Me quiero centrar en programar videojuegos. La API que uso para crearlos es OpenGL |
|
|
|
|
NOB2014
Desconectado
Mensajes: 366
|
class_OpenGL que decir del tiempo que te tomaste, muchas gracias pero muchas gracias, si bien no puedo decir que lo interpreto todo al pie de la letra, con unos pocos repasos ya me ha aclarado bastante el panorama. - A continuación, pongo el código de la función quitar que era lo que me faltaba, con un solo cambio parece que funciona correctamente, lo que me queda duda es como hago para liberar la memoria del nodo que ya no utilizo, lo quería hacer creando un nodo temporal y luego liberarlo desde hay, pero no estoy seguro si es lo correcto. - Elemento *quitar( Elemento *E, int *cantElementos ){ if( *cantElementos > 0 ){ if( *cantElementos == 1){ E = NULL; }else{ inicio = inicio->siguiente; } *cantElementos -= 1; }else{ printf( "\n Cola vacia\n\n Pulse una tecla para continuar..." ); } return E; }
Saludos.
|
|
|
En línea
|
abraza las cosas y personas malas como si fueran tu mas preciada joya,Son tus mas grandes maestros de paciencia sabiduría y amor y cuando lo abrazas dejan de causar dolor.-
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
dudas lenguaje c
Programación C/C++
|
General Dmitry Vergadoski
|
4
|
3,216
|
26 Mayo 2012, 20:27 pm
por Caster
|
|
|
dudas en lenguaje c
Programación C/C++
|
General Dmitry Vergadoski
|
2
|
2,472
|
15 Junio 2012, 23:02 pm
por david_BS
|
|
|
pasar datos de una cola dinámica a otra cola...
Programación C/C++
|
include ();
|
4
|
9,535
|
10 Agosto 2012, 10:01 am
por BlackZeroX
|
|
|
Dudas con cola dinamica
Java
|
Nxyngs
|
0
|
1,615
|
26 Octubre 2013, 00:59 am
por Nxyngs
|
|
|
Segmentation fault en programa con cola enl lenguaje C.
Programación C/C++
|
NOB2014
|
2
|
2,056
|
12 Agosto 2016, 17:08 pm
por AlbertoBSD
|
|