[ Foro de C++ ]

Ejercicio prop. Pag 138

17-May-2013 21:52
Invitado (David24)
5 Respuestas

Buenas de nuevo.
Sigo con el curso y me he quedado atascado en algo. En el ejercicio propuesto de la pagina 138, no se como quedaría el programa ya que siguiendo el curso no he hecho ningún ejemplo de array de estructura con punteros, no se si es que no lo he visto o es que no los hay.
Agradeceria una ayudita.
Os adjunto el programa para poder ver el fallo:


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

main()

{
    struct persona
{
    char nombre[40];
    int edad;
    char ciudad[15];
}; 

int i=1;
int b=0;
int e=0;
int eleccion;
struct persona *persona;
denuevo:
printf ("Para añadir una nueva ficha pulse 0, si desea terminar y ver las fichas existentes pulse 1: \n");
scanf ("%d",&eleccion);
if (eleccion == 0 && i<=100)
{
    printf ("Esta es la ficha numero: %d", i);
    persona = (struct persona*) malloc (sizeof(struct persona));
    printf("Introduzca el nombre de la persona: \n");
    scanf ("%s", persona[i]->nombre);
    printf("Introduzca la edad de la persona (usando numeros): \n");
    scanf ("%d", &persona[i]->edad);
    printf("Introduzca la ciudad de la persona: \n");
    scanf ("%s", persona[i]->ciudad);
    goto denuevo;
    i++;
}
i = b;
for (i=0; i<=b; i++)
{
printf("Persona %d: %s, %s, con edad %d\n",
e+1, persona[i]->nombre, persona[i]->ciudad, persona[i]->edad);
printf ("Persona %d: %s, %s, con edad %d\n", e, persona[i]->nombre, persona[i]->ciudad, persona[i]->edad);
}
free(persona);
getchar();
getchar();

}



18-May-2013 11:48
Nacho Cabanes (+83)

Si te es posible, incluye el enunciado, porque hay varias versiones del curso. Si te refieres a la página 138 de la versión 0.90 (que es la última "disponible para todo el mundo", pero este verano quiero liberar la que estoy revisando), el enunciado sería este:

Mejorar la versión de la agenda que leía todos los datos al principio de la ejecución y guardaba todos los datos cuando terminábamos su uso (apartado 6.4). Esta nueva versión deberá estar preparada para manejar hasta 1000 fichas, pero sólo reservará espacio para las que realmente sean necesarias.

Si es así, necesitarás un array, que tu programa no tiene. Será un array de "punteros a persona", y cada vez que vas a añadir un dato, reservas espacio previamente con "malloc".

Por cierto, no uses "goto" si no es estrictamente inevitable. Y en tu caso, es perfectamente evitable: puedes usar un do-while y el código será más fácil de leer y más razonable.


18-May-2013 13:40
Invitado (David24)

Si, ese es el enunciado exactamente.
Ok lo intento con array.
Me apunto lo del goto, es muy practico para mi, pero se que es menos legible.
Gracias por todo, gran trabajo!!

P.D: ¿Esta este ejercicio resuelto por el foro? Porque no lo encuentro y quiero compararlo.


18-May-2013 16:10
David Garcia

Ya he corregido mi fuente y se lo paso para que lo vea y me diga como lo ve. He intentado que sea legible.


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

struct ficha { 
char nombre[50]; 
char ciudad[50]; 
char edad[3]; 
}; 
//declaramos las variables de forma local para poder usarlas en todas las funciones
struct ficha *datos; /*para cargar en memoria los datos existentes en el fichero*/ 
struct ficha *nueva; /*para ir añadiendo fichas nuevas*/ 
FILE* fichero; 
char agenda[80] ="Mi_agenda.txt"; 
int numFichas=0; 
char textotemporal[10]; 
int tamano=0;
int menu; 
int i; 
int sindatos=0; 

void inicio()
{
    printf("Abriendo agenda...\n"); 
    fichero = fopen(agenda, "rb");  /*abrimos el fichero en modo lectura*/ 
    if (fichero==NULL)  /*si el fichero no existe...*/ 
        printf("Ya que no existe el archivo genda.txt, se va a crear.\nCreado con exito\n"); 
    else    /*si el fichero existe...*/
    {  
        fseek(fichero, 0, SEEK_END); /*saltamos al final del fichero*/ 
        tamano=ftell(fichero); /*tamaño total del fichero*/ 
        numFichas=(tamano/sizeof(struct ficha)); /*El numero de fichas existentes es 
            igual al tamaño total del fichero dividido entre lo que ocupa cada 
            estructura ficha*/
        datos = (struct ficha*) malloc (sizeof(struct ficha) * numFichas);  /*Reservamos 
            el espacio para las fichas existentes*/ 
        if (datos==NULL)    /*Si no hay espacio suficiente, salimos del programa*/ 
        { 
            printf("No hay suficiente espacio en memoria\n"); 
            exit(1); 
        }    
        else
        {
            for (i=0; i<numFichas; i++)   /* y los cargamos en la memoria que hemos reservado*/ 
                fread(datos+i, sizeof(struct ficha), 1, fichero); 
            fclose(fichero);  
        }
    }
}
void menup()
{   
    printf("\nQue desea hacer:\n"); 
    printf("[1] Añadir ficha nueva\n"); 
    printf("[2] Listado de nombres del fichero\n"); 
    printf("[3] Listado total del fichero\n"); 
    printf("[4] Mostrar los datos de una persona\n"); 
    printf("[0] Salir\n"); 
}
void fichanueva()
{   
    if (numFichas<1000)   /*si hay menos de 1000 fichas...*/ 
        { 
            nueva= (struct ficha*) malloc (sizeof(struct ficha)); /*reservamos 
                memoria para una ficha*/ 
            if (nueva==NULL)    /*Si no hay espacio suficiente, salimos del programa*/ 
            { 
                printf("No hay suficiente espacio en memoria\n"); 
                exit(1); 
            } 
            printf("Introduce el nombre: ");/*pedimos datos...*/ 
            gets(nueva->nombre);/*...y los vamos almacenando en su posición*/ 
            printf("Introduce la ciudad: "); 
            gets(nueva->ciudad); 
            printf("Introduce la edad: "); 
            gets(nueva->edad); 
            numFichas++; 
            fichero = fopen(agenda, "ab"); /*abrimos el fichero*/
            fwrite(nueva, sizeof(struct ficha), 1, fichero); /*escribimos los datos de la ficha*/
            fclose(fichero); /*cerramos el fichero*/ 
            free(nueva); /*liberamos memoria*/ 
            printf("Abrimos el fichero, escribimos los datos,cerramos el fichero y liberamos memoria\n"); 
        }
        else 
            printf("No hay sitio para mas fichas (maximo 1000)"); /*si hay mas 
                de 1000 fichas, avisamos*/ 
}
void imprimirnombres()
{
    free(datos);    /*primero liberamos de la memoria los datos que había hasta ahora*/ 
        fichero = fopen(agenda, "rb");   /*abrimos el fichero en modo lectura*/ 
        if (fichero==NULL)  /*si el fichero no existe...*/ 
            printf("No hay datos.\n"); 
        else    /*si el fichero existe...*/  
        { 
            datos = (struct ficha*) malloc (sizeof(struct ficha) * numFichas); /*Reservamos 
                el espacio para las fichas existentes*/ 
            if (datos==NULL) /*Si no hay espacio suficiente, salimos del programa*/ 
            { 
            printf("No hay suficiente espacio en memoria\n"); 
            exit(1);  
            } 
            while (!feof(fichero))  /*Leemos todos los datos hasta el final del fichero*/ 
            { 
                for (i=0; i<numFichas; i++)   /* y los cargamos en la memoria que hemos reservado*/ 
                fread(datos+i, sizeof(struct ficha), 1, fichero); 
            } 
            fclose(fichero); /*Cerramos el fichero*/ 
        } 
        printf("Los nombres existentes son:\n");  /*sacamos los datos por pantalla*/ 
        for (i=0; i<numFichas; i++)  
            printf("%s\n", (datos+i)->nombre);
}    
void imprimirtodo()
{
    free(datos); /*primero liberamos de la memoria los datos que había hasta ahora*/ 
        fichero = fopen(agenda, "rb"); /*abrimos el fichero en modo lectura*/ 
        if (fichero==NULL)  /*si el fichero no existe...*/ 
            printf("No hay datos.\n"); 
        else    /*si el fichero existe...*/ 
        { 
            datos = (struct ficha*) malloc (sizeof(struct ficha) * numFichas); /*Reservamos 
                el espacio para las fichas existentes*/ 
            if (datos==NULL)    /*Si no hay espacio suficiente, salimos del programa*/ 
            { 
                printf("No hay suficiente espacio en memoria\n"); 
                exit(1); 
            } 
            while (!feof(fichero)) /*Leemos todos los datos hasta el final del fichero*/ 
            { 
                for (i=0; i<numFichas; i++)/* y los cargamos en la memoria que hemos reservado*/ 
                    fread(datos+i, sizeof(struct ficha), 1, fichero); 
            } 
            fclose(fichero); /*Cerramos el fichero*/ 
        } 
        printf("Los datos existentes son:\n");   /*sacamos los datos por pantalla*/ 
        for (i=0; i<numFichas; i++) 
            printf("%s vive en %s y su edad es de %s \n", (datos+i)->nombre, 
                (datos+i)->ciudad, (datos+i)->edad);
}
void unapersona()
{
    free(datos); /*primero liberamos de la memoria los datos que había hasta ahora*/ 
        fichero = fopen(agenda, "rb"); /*abrimos el fichero en modo lectura*/ 
        if (fichero==NULL)  /*si el fichero no existe...*/ 
            printf("No hay datos.\n"); 
        else    /*si el fichero existe...*/  
        { 
            datos = (struct ficha*) malloc (sizeof(struct ficha) * numFichas); /*Reservamos 
                el espacio para las fichas existentes*/ 
            if (datos==NULL)    /*Si no hay espacio suficiente, salimos del programa*/ 
            { 
                printf("No hay suficiente espacio en memoria\n"); 
                exit(1);   
            } 
            while (!feof(fichero))  /*Leemos todos los datos hasta el final del fichero*/ 
            { 
                for (i=0; i<numFichas; i++) /* y los cargamos en la memoria que hemos reservado*/ 
                    fread(datos+i, sizeof(struct ficha), 1, fichero); 
            } 
            fclose(fichero); /*Cerramos el fichero*/ 
        } 
        printf("Escribe el nombre a buscar: ");    /*sacamos los datos por pantalla*/ 
        gets(textotemporal); 
        sindatos = 0; /*Inicializamos la variable que nos dirá si ha encontrado coincidencias o no*/ 
        for (i=0; i<numFichas; i++) 
        { 
            if (strcmp((datos+i)->nombre, textotemporal)==0) /*hacemos la
                comparacion, si existe el nombre escribimos los datos*/ 
            {
                printf("Los datos que disponemos para %s son:\n", textotemporal); 
                printf("%s vive en %s y su edad es %s\n",(datos+i)->nombre, 
                    (datos+i)->ciudad, (datos+i)->edad); 
                sindatos++; /*y la variable sindatos cambia de valor*/ 
            } 
        } 
        if (sindatos==0) /*Si la variable sindatos sigue 
            siendo igual a 0 es que no ha encontrado el nombre, cosa que indicamos*/ 
            printf("No se disponen de datos para %s.\n", textotemporal);
}
main() 
{	
    inicio();
    do 
    { 
        menup();
        gets(textotemporal); 
        sscanf(textotemporal, "%d", &menu); 
        switch (menu)
        { 
            case 1: 
            fichanueva();
            break; 

            case 2:   /*Refrescamos los datos del fichero*/ 
            imprimirnombres(); 
            break; 

            case 3:    /*Refrescamos los datos del fichero*/ 
            imprimirtodo(); 
            break; 

            case 4:   /*Refrescamos los datos del fichero*/ 
            unapersona();
            break; 
        
            case 0: 
            printf("Hasta la vista!"); 
            free(datos); 
            break; 

            default: 
            printf("Opcion no valida"); 
            break; 
        } 
    } while (menu != 0); 
}




P.D: No se si es que no entendí bien el ejercicio o que hay alguna errata pero creo que si creo un array de estructura (aunque sea con punteros) de [1000] fichas estamos haciéndolo estático, ¿no?. De ahí mi pregunta.
Gracias por todo, espero su valoración.


19-May-2013 01:39
Nacho Cabanes (+83)

Veamos...

Se acerca bastante. Pero el array... no lo estás usando: cuando se pide un nuevo dato, lo vuelcas a fichero, y cuando vas a mostrar, lees todo desde fichero. Se trata de que cada nuevo dato vaya a parar al array, y sólo se guardan los datos al final de la ejecución (y se cargan al principio de la siguiente).

Por cierto, intenta no hacer líneas de más de 80 caracteres de longitud. Se descuadran al imprimir y desbordarán la anchura en el foro de modo que aquí también se leerán mal. Te he partido alguna de las más largas, para que se pudieran leer (o casi) en el foro.

Y tienes razón: esta aproximación no es totalmente dinámica, como lo sería una lista enlazada. Pero tampoco es totalmente estática, porque estás reservando inicialmente 1000 datos x 4 bytes cada uno (que es lo que ocupa un puntero en un sistema de 32 bits), y el espacio real que ocupará cada ficha (103 bytes en tu fuente) lo solicitas al sistema justo cuando te van a introducir esa ficha. De este modo, si sólo tienes 10 de las 1000 fichas, no usas 103.000 bytes, sino 4.206 (4000 del array de punteros y 103x2 de las dos fichas).


20-May-2013 01:03
Invitado (David24)

Muchas gracias maestro. Gran trabajo!






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)