Problema con LISTAS y un switch.

Iniciado por flowrd23, 4 Julio 2019, 20:49 PM

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

flowrd23

Estoy empezando a entender listas, tengo el siguiente problema: El menú de opciones vuelve a repetirse indefinidamente luego de devolver "inicio", en vez de volver a solicitar una opción al usuario ¿Qué anda mal?


/*5 El programa para ubicar un disco de una colección de música que se encuentra ordenada en
estantes debe tener los siguientes datos:
a Nombre el disco
b Grupo musical
c Soporte (vinilo, CD, cassette)
d Año de lanzamiento
e Categorı́a (clásica, jazz, folclore, tango, etc)
f Ubicación (estante en el cual se encuentra)
5.1 La base de datos debe crecer y decrecer dinámicamente.
5.2 Debe permitir buscar y mostrar la búsqueda de cualquiera de los datos miembro.
5.3 Debe permitir el ordenamiento.*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct NODO {
char nombre[31];
char grupo[31];
int year;
char categoria[31];
struct NODO *siguiente;
}NODO;

void crearLista(NODO *);//ASÍ ES *crearLista(), ES UNA FUNCIÓN QUE DEBERÍA DEVOLVER UN PUNTERO A UN TIPO NODO.
//Y en el argumento de la función tenemos que necesita recibir un puntero a un tipo de struct NODO.
int main(){
NODO *inicio=NULL;
int OPTION=0;
puts("Ingrese una opción.\n");


do{
printf("1- AGREGAR ARTISTA A LA LISTA \n2-BUSCAR GRUPO MUSICAL EN LA LISTA\n3-LISTAR TODO LOS DATOS\n4-SALIR\n\n");
scanf("%d", &OPTION);

switch(OPTION){
case 1:
puts("Ingrese los datos del grupo: \n");
crearLista(inicio);
break;
break;
case 2:
puts("NOT AVAIBLE");
break;
case 3:
puts("NOT AVAIBLE");
break;
//default: printf( "Opción no válida\n" );
                //break;
}
  }while(OPTION !=4);
return 0;
}
void crearLista(NODO *inicio){


NODO *ptr, *newNodo;
newNodo= (NODO *) malloc(sizeof(NODO));
if(newNodo==NULL){
printf("OUT OF MEMORY.\n");
}
printf("Nombre:\n ");
gets(newNodo->nombre);
getchar();
printf("Grupo:\n ");
gets(newNodo->grupo);
getchar();
puts("\nAño de lanzamiento: ");
gets(&newNodo->year);
getchar();
puts("\nCategoría: ");
gets(newNodo->categoria);
getchar();
if(inicio==NULL){
newNodo->siguiente=NULL;
inicio=newNodo;

}else{
ptr=inicio;
while(ptr->siguiente!=NULL){
ptr=ptr->siguiente;
}
ptr->siguiente=newNodo;
newNodo->siguiente=NULL;
      }

}

K-YreX

El programa parece que funciona correctamente...
Si tu problema es que no se vuelve a mostrar lo de "Ingrese una opcion\n" es porque se encuentra fuera del <do while>. Si no te refieres a eso, manda la salida de tu programa y especifica cuál es el problema ya que yo al menos no lo encuentro  :-X
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

flowrd23

Muchas gracias por responder.
El problema es que vuelve a ingresar automáticamente a la opción 1 luego de ingresar el primer el primer dato a la lista.
Una captura:
https://ibb.co/jyyWwX3

RayR

#3
No lo ejecuté, pero tienes varios errores. Primero, la recomendación es que uses fgets en lugar de gets, pues esta última es una función insegura. Pasando a los errores, uno es que estás leyendo year con gets, pero year es un int, por lo que gets está sobrescribiendo memoria incorrectamente y obviamente year queda con basura. Usa scanf.

Otro, el getchar que usas es para eliminar el caracter de nueva línea '\n' que algunas funciones dejan en el buffer de entrada, pero gets no es una de esas funciones, por lo que, en tu programa, los getchar lo unico que ocasionan es que el primer caracter de la siguiente línea introducida sea descartado, es decir, en el ejemplo de la captura que pusiste, lo que en realidad se estaría almacenando en grupo es "ammstein", ya que la "R" es leída y removida por el getchar que le precede. Debes borrar todos los getchar y sólo ponerlos después de los scanf, que sí dejan el '\n'.

Y el que quizás sea el más importante, el parámetro de crearLista es de tipo incorrecto. Como sabrás, cuando quieres que una función sea capaz de modificar una variable (como un int, float, etc.) que le pases como argumento, hay que hacerlo por referencia, que en C significa pasar un puntero a dicha variable. Lo mismo pasa con los punteros: si quieres modificar un puntero (no sólo los valores a los que apunta, sino el propio puntero), debes pasarle un puntero a puntero. Porque tal como lo tienes, crearLista recibe una copia del puntero inicio, por lo que cuando haces esto:

inicio=newNodo;

lo que estás modificando es la copia de inicio que sólo existe dentro de crearLista. Al regresar a main, inicio (la variable local de main) seguirá apuntando a NULL. Cambia el prototipo y la definición de la función a:

void crearLista(NODO **inicio)

y dentro de esa función, donde ponías inicio, pon *inicio. Y la invocas así:

crearLista(&inicio);

Te reitero que no lo probé, por lo que no sé si haya más errores, pero esto debería corregir al menos el problema que tienes actualmente.

flowrd23

Gracias....
Cómo uso el fgets?
Traté de usar para una sola entrada para el miembro nombre (ignorando y borrando los demás miembros de la estructura nodo) :  fgets(nuevo->nombre, 31, stdin);  y NO FUNCIONA....
/*5 El programa para ubicar un disco de una colección de música que se encuentra ordenada en
estantes debe tener los siguientes datos:
a Nombre el disco
b Grupo musical
c Soporte (vinilo, CD, cassette)
d Año de lanzamiento
e Categorı́a (clásica, jazz, folclore, tango, etc)
f Ubicación (estante en el cual se encuentra)*/
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo{
char album[50];
char nombre[50];
char soporte[31];
int year;
char category[31];
int ubicacion;
struct nodo *siguiente;
}nodo;
void ingresar_Nodo();
void desplegar_Lista();
nodo *primero=NULL;
nodo *ultimo=NULL;
FILE *a;
int main(){
puts("----BIENVENIDO---\t\n");
int OPTION;
do{
printf("1) Ingresar álbum.\n 2) Desplegar la lista completa de discos.\n 3)SALIR.\n");
scanf("%d", &OPTION);
switch(OPTION){
case 1:
ingresar_Nodo();
break;
case 2:
desplegar_Lista();
break;
}
}while(OPTION!=3);
return 0;
}
void ingresar_Nodo(){
nodo *nuevo=(nodo *) malloc(sizeof(nodo));

printf("Ingrese datos del álbum:\n");
printf("Album: ");
scanf("%s", nuevo->album);
fflush(stdout);
printf("Nombre:");
scanf("%s",nuevo->nombre);
fflush(stdout);
printf("Soporte: ");
scanf("%s",nuevo->soporte);
fflush(stdout);
printf("Año: ");
scanf("%d",&nuevo->year);
printf("Categoría: ");
scanf("%s",nuevo->category);
fflush(stdout);
printf("Ubicación física: ");
scanf("%d",&nuevo->ubicacion);
nuevo->siguiente=NULL;
if(primero==NULL){
primero=nuevo;
ultimo=nuevo;
}else{
ultimo->siguiente=nuevo;
ultimo=nuevo;
}

}
void desplegar_Lista(){
puts("\tDESPLEGANDO LISTA COMPLETA....\n");
nodo *auxiliar=(nodo *) malloc(sizeof(nodo));
int i=0;
auxiliar=primero;
while(auxiliar!=NULL){
printf("%s\n %s\n %s\n %d\n %s\n %d\n\n", auxiliar->album, auxiliar->nombre, auxiliar->soporte, auxiliar->year, auxiliar->category, auxiliar->ubicacion);
auxiliar=auxiliar->siguiente;
i++;
}if(i==0){
puts("LISTA VACÍA!\n");
}
}



flowrd23

Respecto al código anterior, es funcional con scanf si las entradas de palabras no tienen espacio.  Cómo incorporo correctamente fgets? probé cambiando todos los scanf que reciben caracteres con fgets pero así lo pasa por alto y vuelve al menú...
Necesito resolver esto, para avanzar más.

K-YreX

No creo que tenga ninguna complicación. En internet habrá infinidad de ejemplos al igual que en otros temas de este foro...

char nombre[50];

printf("Introduce tu nombre: ");
fgets(nombre, 50, stdin);

printf("Tu nombre es: %s", nombre); // se mostrara "Tu nombre es: <nombre>\n" (con salto de linea al final)

PD: Ten cuidado ya que <fgets()> guarda también el salto de línea de cuando das al ENTER.

Y el problema que tendrás será porque tienes cosas en el buffer (saltos de línea seguramente) y no lo limpias. Es cierto que todo el mundo usa la función <fflush(stdin)> de forma incorrecta ya que <fflush()> está diseñada para trabajar con <stdout> pero obviamente no hace lo mismo. Tienes otras alternativas para limpiar el buffer que se comentaron en un tema de este foro de C/C++.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;

flowrd23

Ya intenté probando limpiadores de buffers...fflush, .....getchar, etc. NO CONSIGO solución, ahora me saltea los scanf que levantan  año y ubicación.
void ingresar_Nodo(){
nodo *nuevo=(nodo *) malloc(sizeof(nodo));

printf("Ingrese datos del álbum:\n");
printf("Album: ");
fgets(nuevo->album, 50, stdin);
getchar();
//scanf("%s", nuevo->album);
//fflush(stdout);
printf("Nombre:");
fgets(nuevo->nombre, 50, stdin);
getchar();
//scanf("%s",nuevo->nombre);
//fflush(stdout);
printf("Soporte: ");
fgets(nuevo->soporte, 31, stdin);
getchar();
printf("Año:");
scanf("%d", &nuevo->year);
getchar();
printf("\nCategoría: ");
fgets(nuevo->category, 31, stdin);
getchar();
//scanf("%s",nuevo->category);
//fflush(stdout);
printf("Ubicación física: ");
scanf("%d",&nuevo->ubicacion);

nuevo->siguiente=NULL;
if(primero==NULL){
primero=nuevo;
ultimo=nuevo;
}else{
ultimo->siguiente=nuevo;
ultimo=nuevo;
}

}

K-YreX

Tienes que saber cuándo tienes algo en el buffer y cuando no. Si no tienes nada y pones un <getchar()> el programa espera un ENTER, entonces tienes que darlo antes de que te salga el siguiente mensaje y puedas introducir el siguiente dato. En tu caso sobran <getchar()> ya que <fgets()> guarda el ENTER dentro del nombre y no son necesarios pero si tienes problemas será que estás sobrepasando el límite de tamaño que tienes establecido.

Si cambiando el tamaño no consigues solucionarlo coloca un ejemplo de ejecución para poder verlo con más detalle.
Código (cpp) [Seleccionar]

cout << "Todos tenemos un defecto, un error en nuestro código" << endl;