UTNianos

Versión completa: Consulta Ej. 2 de la guia operativos
Actualmente estas viendo una versión simplificada de nuestro contenido. Ver la versión completa con el formato correcto.
Estoy practicando C con mi grupo antes de cursar , y quisiera saber si esta bien encarado el ejercicio de la guia:

Ejercicio 2 (Modelado de TADs)
Se pide modelar un TAD que represente un Archivo, se debe poder abrir (definir la forma: read/write/append), cerrar un archivo, leer una linea determinada, exponer una operación que reciba una función y la ejecute por cada línea del archivo; exponer otra operación que dada una lista y una función, itere la lista y escriba sobre el archivo abierto.

Guia: https://docs.google.com/document/d/1n_u1...edit?pli=1



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

typedef FILE ARCHIVO;
ARCHIVO *abrir(char *nombre, char *modo);
int cerrar(ARCHIVO *p);
char *leerlinea(char *linea, int maxlinea, ARCHIVO *p);
void operacion( unsigned int(*f)(const char *) , ARCHIVO *p);

int main(void){

ARCHIVO *fp;

char *linea=(char *)malloc(sizeof(char)*1000);
char *linealeida=(char *)malloc(sizeof(char)*1000);

if((fp=abrir("prueba.txt", "leer"))==NULL){
fprintf(stderr, "no se pudo abrir");
exit(1);
}

printf("Ya esta abierto, y ahora leo la primer linea\n");

if((linealeida=leerlinea(linea, 1000, fp))==NULL){
fprintf(stderr, "no se pudo leer linea");
exit(1);
}

printf(" la linea era: %s \n", linealeida);

printf("Ahora hago la operacion mandando la funcion strlen: \n");

operacion(strlen, fp);

cerrar(fp);

free(linea);
free(linealeida);

printf("ya se cerro\n");

return 0;
}



ARCHIVO *abrir(char *nombre, char *modo){

if(strcmp(modo, "leer")==0)
return fopen(nombre,"r");

if(strcmp(modo, "escribir")==0)
return fopen(nombre,"w");

if(strcmp(modo, "apend")==0)
return fopen(nombre,"a");

fprintf(stderr, "Modo mal escrito, hay 3: leer, escribir, o apend");
exit(1);
}


int cerrar(ARCHIVO *p){

return fclose(p);

}


char *leerlinea(char *linea, int maxlinea, ARCHIVO *p){

return fgets(linea, maxlinea, p);
}


void operacion( unsigned int(*f)(const char *) , ARCHIVO *fp){

char *l=(char *)malloc(sizeof(char)*1000);
char *leida=(char *)malloc(sizeof(char)*1000);


while((leida=leerlinea(l, 1000, fp))!=NULL)
printf("%d \n", (*f)(leida) );

free(l);
free(leida);


return;
}




Lo probamos con un archivo prueba.txt con algunas lineas y todo anda bien, lo que faltaria es hacer un .h para el typedef y los prototipos de función calculamos

Muchas Gracias!
para empezar estan usando memoria dinamica al pedo, la gracia de usar memoria dinamica es pedir una cantidad de memoria que no se conoce hasta tiempo de ejecucion, por lo tanto deberian usar memoria estatica (porque ya saben de antemano cuanta memoria van a utilizar) char linea[1000]; y char linealeida[1000];

otra recomendacion es que no dejen numeros magicos en el programa si van a poner 1000 hagan un define

#define MAX_LINE 1000
Esta encarado, pero le veo un par de inconvenientes técnicos como teoricos:

Un TAD en general se tiene un .h con las operaciones que expone y un .c que las implementa, entonces deberías tener 3 archivos en este caso, el main.c, el archivo.h y archivo.c. Una convención que capaz te sirva para identificar rápidamente que funciones son de un tad y no de la lib estandar es usar la siguiente nomenclatura. <nombre_tad>_<operacion>, igual esto es solo una convención. Seguramente pusiste todo junto para postearlo, así que no hay drama.

Problema técnico, el leerLinea avanza el puntero dentro del archivo, por lo tanto si luego llamas a la función operacion (nombre mas expresivo, podría ser, iterar_lineas ;) ), entonces esta va a iterar sobre las siguientes lineas, y en realidad debe aplicarse a todas las lineas del archivo. Capaz entonces no debería recibir el file abierto, sino un path, ya que no tendría que realizar ninguna operación que tenga efecto sobre el archivo

Este código tiene un par de inconvenientes

char *l=(char *)malloc(sizeof(char)*1000);
char *leida=(char *)malloc(sizeof(char)*1000);
while((leida=leerlinea(l, 1000, fp))!=NULL)
printf("%d \n", (*f)(leida) );

free(l);
free(leida);



Para leída no hace falta reservar memoria, ya que si te fijas el fgets(..) devuelve el parametro que le pasas para que escriba o NULL, por lo tanto te estaría devolviendo la memoria que reservaste en l y la que reservaste en leida se pierde en el limbo de la memoria (lo que se conoce como leak), además si l y leida apuntan a lo mismo, entonces el primer free todo bien, pero cuando hagas el segundo free va a chillar diciendo flaco ya liberaste esta memoria ;)

Una duda, donde lo probaste, linux o windows? porque en general los doble free explotan rápido en linux =)

A una cosa más, si tenes una cantidad definida de valores, podes usar enums(http://stackoverflow.com/questions/11025...-enum-in-c) en vez de strings
Cita:Esta encarado, pero le veo un par de inconvenientes técnicos como teoricos:

Un TAD en general se tiene un .h con las operaciones que expone y un .c que las implementa, entonces deberías tener 3 archivos en este caso, el main.c, el archivo.h y archivo.c. Una convención que capaz te sirva para identificar rápidamente que funciones son de un tad y no de la lib estandar es usar la siguiente nomenclatura. <nombre_tad>_<operacion>, igual esto es solo una convención. Seguramente pusiste todo junto para postearlo, así que no hay drama.

Hice todo junto para entenderme y después iba a hacer la división de los archivos como vos decis en main.c archivo.h archivo.c

Cita:Problema técnico, el leerLinea avanza el puntero dentro del archivo, por lo tanto si luego llamas a la función operacion (nombre mas expresivo, podría ser, iterar_lineas ;) ), entonces esta va a iterar sobre las siguientes lineas, y en realidad debe aplicarse a todas las lineas del archivo. Capaz entonces no debería recibir el file abierto, sino un path, ya que no tendría que realizar ninguna operación que tenga efecto sobre el archivo

Esto lo tenia en cuenta y me olvide de comentarlo, al ejecutar la función operación, itera desde la 2da linea como decis, porque se me dio por probar todo junto y hice lio !

Cita:Este código tiene un par de inconvenientes

char *l=(char *)malloc(sizeof(char)*1000);
char *leida=(char *)malloc(sizeof(char)*1000);
while((leida=leerlinea(l, 1000, fp))!=NULL)
printf("%d \n", (*f)(leida) );

free(l);
free(leida);



Para leída no hace falta reservar memoria, ya que si te fijas el fgets(..) devuelve el parametro que le pasas para que escriba o NULL, por lo tanto te estaría devolviendo la memoria que reservaste en l y la que reservaste en leida se pierde en el limbo de la memoria (lo que se conoce como leak), además si l y leida apuntan a lo mismo, entonces el primer free todo bien, pero cuando hagas el segundo free va a chillar diciendo flaco ya liberaste esta memoria ;)

Una duda, donde lo probaste, linux o windows? porque en general los doble free explotan rápido en linux =)

Claro, entiendo el problema,pero me estoy volviendo loco porque probe en linux(eclipse), y windows y no me salta el problema tener muchos free a la misma cosa. Hasta probe poner tres free(leida); seguidos para que saltara algo y no salta...
Creo que también debería dejar de usar memoria dinamica que esta al pedo y usar estatica (como dijo Virus).


Cita:A una cosa más, si tenes una cantidad definida de valores, podes usar enums(http://stackoverflow.com/questions/11025...-enum-in-c) en vez de strings

No entendi, en que lugar decís que podría reemplazar strings por enums?


Muchísimas gracias por la ayuda, la verdad me sirve muchísimo!
Cita:Claro, entiendo el problema,pero me estoy volviendo loco porque probe en linux(eclipse), y windows y no me salta el problema tener muchos free a la misma cosa. Hasta probe poner tres free(leida); seguidos para que saltara algo y no salta...
Creo que también debería dejar de usar memoria dinamica que esta al pedo y usar estatica (como dijo Virus).

Ah.. yo lo probe desde la consola =P
Si, la del array sirve, a menos que quieran que implementes una lectura que no tenga un tamaño máximo y sea tu tarea identificar como hacerlo para que no hay limite,

Es media inconsiste la interfaz que proponen porque por un lado pareciera que tenes que abrir y operar sobre un archivo abierto, y en otros momentos parece que fuera un archivo sin abrir, pero bueno.. capaz la idea es que te des cuenta que hay que diferenciarlas o capaz la pifiaron XD


Cita:No entendi, en que lugar decís que podría reemplazar strings por enums?

Yo decía en el abrir, en vez de usar strings para indicar el modo podrías usar un enum
(21-03-2014 01:58)dezine18 escribió: [ -> ]
Cita:Claro, entiendo el problema,pero me estoy volviendo loco porque probe en linux(eclipse), y windows y no me salta el problema tener muchos free a la misma cosa. Hasta probe poner tres free(leida); seguidos para que saltara algo y no salta...
Creo que también debería dejar de usar memoria dinamica que esta al pedo y usar estatica (como dijo Virus).

Ah.. yo lo probe desde la consola =P
Si, la del array sirve, a menos que quieran que implementes una lectura que no tenga un tamaño máximo y sea tu tarea identificar como hacerlo para que no hay limite,

Es media inconsiste la interfaz que proponen porque por un lado pareciera que tenes que abrir y operar sobre un archivo abierto, y en otros momentos parece que fuera un archivo sin abrir, pero bueno.. capaz la idea es que te des cuenta que hay que diferenciarlas o capaz la pifiaron XD


Cita:No entendi, en que lugar decís que podría reemplazar strings por enums?

Yo decía en el abrir, en vez de usar strings para indicar el modo podrías usar un enum

Sii, tenes razon, ahi queda mucho mejor un enum, no me daba cuenta!
Y el ejercicio es un poco confuso, pero con todo esto aprendi un monton jaja gracias!
Ahhh, una boludez más sintactica, si tenes un puntero a función, para evaluarlo no hace falta desreferenciarlo, podes hacer: f(p) en vez de (*f)(p)
URLs de referencia