[Solucionado] Problema con lista enlazada en C (buffer de entrada)

Iniciado por xassiz~, 20 Febrero 2011, 17:02 PM

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

xassiz~

#Solucion del post

Bueno, estaba practicando con listas enlazadas en C, pero no se porque no me va esto :xD

El caso es que no me deja ingresar bien los datos, ¿uso mal fgets()?

Código (c,21,23,45) [Seleccionar]

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct _contacto {
   char nombre[33];
   char telefono[13];
   struct _contacto *siguiente;
};
struct _contacto *primero, *ultimo;

void agregar_contacto()
{
    struct _contacto *nuevo;
    nuevo = (struct _contacto*)malloc(sizeof(struct _contacto));
    if(nuevo==NULL){
        printf("\nNo hay espacio suficiente.");
        return;
    }
    printf("\n\nAgregar contacto\n");
    printf("------------------");
    printf("\nNombre: ");
    fgets(nuevo->nombre,32,stdin);
    printf("\nTelefono: ");
    fgets(nuevo->telefono,12,stdin);
    nuevo->siguiente = NULL;
    if(primero==NULL){
        primero = nuevo;
        ultimo = nuevo;
    } else {
        ultimo->siguiente = nuevo;
        ultimo = nuevo;
    }
}

void buscar_contacto_tlfn()
{
    struct _contacto *busqueda, *actual;
    busqueda = (struct _contacto*)malloc(sizeof(struct _contacto));
    if(busqueda==NULL){
        printf("\nNo hay espacio suficiente.");
        return ;
    }
    printf("\n\nBuscar contacto por telefono\n");
    printf("----------------------------");
    printf("\nTelefono: ");
    fgets(busqueda->telefono,12,stdin);
    actual = primero;
    while(actual!=NULL){
        if(strcmp(actual->telefono,busqueda->telefono)==0){
            printf("+Nombre: %s\n", actual->nombre);
            return;
        }
        actual = actual->siguiente;
    }
    printf("No encontrado.");
}


int opcion = 0;

void mostrar_menu()
{
    opcion = 0;
    printf("\n\n\n MENU\n");
    printf("======\n");
    printf("1. Agregar contacto\n");
    printf("2. Buscar contacto por telefono\n");
    printf("3. Salir\n");
    scanf("%i", &opcion);
}

int main()
{
   while(opcion!=3){
       mostrar_menu();
       switch(opcion)
       {
           case 1:
               agregar_contacto();
               break;
           case 2:
               buscar_contacto_tlfn();
               break;
           default:
               break;
       }
   }
   return 0;
}


Saludos!

Shut

#1
Hola, bueno lo primero que tienes que incluir la libreria <stdlib.h> para usar la malloc. El problema que sugieres al intentar meter los nombres, es porque el fgets suele dar problemas.Es porque se queda en el buffer del teclado el intro y por eso te salta una opcion del menu.Deberias poner antes de cada fgets, fflush(stdin) para limpiar el buffer y que no te salte.

xassiz~

#2
Cita de: Shut en 20 Febrero 2011, 19:45 PM
s porque se queda en el buffer del teclado el intro y por eso te salta una opcion del menu.Deberias poner antes de cada gets, fflush(stdin) para limpiar el buffer y que no te salte.
Gracias, funciona, pero en este post fijado dicen que fflush(stdin); es mala costumbre y que lo del buffer debería darme problemas con scanf() pero no con fgets() :-X


Shut

Bueno pues entonces si no la quieres usar puedes probar lo del post, es una solucion mejor parece ser, es comprobar si se quedo almacenado un salto de linea en esa posicion, y si es asi mete un nulo. Puedes probar, y si funciona pues mejor. Sino siempre quedara fflush(stdin) xdd

Voi a comprobar yo si me funciona con lo de poner el nulo  :)

Leber

Puedes meter un '\0' directamente. Así es como yo lo hago.

#include <stdio.h>
#include <string.h>

int
main(int argc, char **argv)
{

        char test[20];

                fgets(test, sizeof(test)-1, stdin);
                test[strlen(test)-1] = '\0';
                printf("%s\n", test);
                return 0;
}

"Solo los tontos carecen de preucupaciones." Johann Wolfgang Goethe

xassiz~

Pero lo de cambiar el salto por línea por el caracter nulo sería en el momento de elegir la opción en el menú, ¿no?

En ese caso tengo que reemplazar el scanf() por fgets() y poner la variable opcion como un arreglo de caracteres :-X

D4RIO

OpenBSDFreeBSD

Littlehorse

Las variables globales son perjudiciales para la salud, trata de evitarlas siempre que sea posible.


Cita de: pablomi en 20 Febrero 2011, 20:44 PM
En ese caso tengo que reemplazar el scanf() por fgets() y poner la variable opcion como un arreglo de caracteres :-X

Efectivamente. La forma mas segura de realizar un ingreso de datos por parte del usuario es leyendo como texto y luego parseando y validando lo necesario.

Saludos
An expert is a man who has made all the mistakes which can be made, in a very narrow field.

xassiz~

#8
Bueno, ya me deshice de variables globales y de los scanf(), pero curiosamente sigue pasando el mismo error :xD


#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct _contacto {
   char nombre[33];
   char telefono[13];
   struct _contacto *siguiente;
};
struct _contacto *primero, *ultimo;

void agregar_contacto()
{
    struct _contacto *nuevo;
    nuevo = (struct _contacto*)malloc(sizeof(struct _contacto));
    if(nuevo==NULL){
        printf("\nNo hay espacio suficiente.");
        return;
    }
    printf("\n\nAgregar contacto\n");
    printf("------------------");
    printf("\nNombre: ");
    fgets(nuevo->nombre,32,stdin);
    printf("\nTelefono: ");
    fgets(nuevo->telefono,12,stdin);
    nuevo->siguiente = NULL;
    if(primero==NULL){
        primero = nuevo;
        ultimo = nuevo;
    } else {
        ultimo->siguiente = nuevo;
        ultimo = nuevo;
    }
}

void buscar_contacto_tlfn()
{
    struct _contacto *busqueda, *actual;
    busqueda = (struct _contacto*)malloc(sizeof(struct _contacto));
    if(busqueda==NULL){
        printf("\nNo hay espacio suficiente.");
        return ;
    }
    printf("\n\nBuscar contacto por telefono\n");
    printf("----------------------------");
    printf("\nTelefono: ");
    fgets(busqueda->telefono,12,stdin);
    actual = primero;
    while(actual!=NULL){
        if(strcmp(actual->telefono,busqueda->telefono)==0){
            printf("+Nombre: %s\n", actual->nombre);
            return;
        }
        actual = actual->siguiente;
    }
    printf("No encontrado.");
}


char mostrar_menu()
{
    char opcion[3];
    printf("\n\n\n MENU\n");
    printf("======\n");
    printf("1. Agregar contacto\n");
    printf("2. Buscar contacto por telefono\n");
    printf("3. Salir\n");
    fgets(opcion,2,stdin);
    return opcion[0];
}

int main()
{
   char opcion='0';
   while(opcion!='3'){
       opcion = mostrar_menu();
       if(opcion=='1')
           agregar_contacto();
       else if(opcion=='2')
           buscar_contacto_tlfn();
   }
   return 0;
}


Saludos!

Littlehorse

Es que de la forma que haces la lectura, fgets nunca llega a leer el salto de linea por lo tanto nada puede hacer con el.

Si tenes una cadena de 3 posiciones, y a fgets le pasas como parámetro que lea solo 2, en realidad lee 2-1. Es decir, lee 1 solo carácter, luego agrega el carácter nulo a la cadena, y el salto de linea queda deambulando por el buffer de entrada.


Citar
Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or a the End-of-File is reached, whichever comes first.
A newline character makes fgets stop reading, but it is considered a valid character and therefore it is included in the string copied to str.
A null character is automatically appended in str after the characters read to signal the end of the C string.
Cuando dije leer como texto me referia a leer y analizar una expresion para verificar si el usuario ha ingresado la opción correctamente. Lo que estas haciendo ahora es utilizar una cadena como si fuese un solo carácter y aunque es legal no es del todo correcto.

Saludos!
An expert is a man who has made all the mistakes which can be made, in a very narrow field.