[C con Clase] Duda con función que retorna un puntero a una estructura que no está funciona

Davidson, Steven srd4121 en njit.edu
Mar Dic 19 17:34:52 CET 2017


Hola Personal,

Me voy a fijar exclusivamente en la función, 'LoadCardNumberInfo()'. Veamos
algunos errores:

- Escribes:

pindex = malloc (sizeof (&pindex));

Estás creando memoria para un puntero y no para una estructura, que es lo
que te interesa. Deberías escribir:

pindex = malloc( sizeof (CARDFILEINDEX) );

- Al final escribes,

free (&pindex);

Esto es incorrecto, porque intentas liberar la memoria de la variable,
'pindex'. Lo que te interesa es liberar la memoria dinámica que previamente
adjudicaste. Esto es,

free( pindex );

- Al terminar la función retornas el valor guardado en 'pindex'. El
problema es que esta dirección de memoria ya no es válida, porque la has
liberado. Por lo tanto, al retornar no tendrías acceso a la información en
la estructura.

Una solución elegante es pasar la variable de la estructura por parámetro.
Por ejemplo,

PINDEX LoadCardNumberInfo( PINDEX pindex, FILE *fileptr, int card_number )
{
  ...
  return pindex;
}

Esto obliga al código que invoca esta función a crear la estructura y por
tanto su memoria sigue vigente antes y después de invocar a
'LoadCardNumberInfo()'. Por ejemplo,

CARDFILEINDEX cfi;

LoadCardNumberInfo( &cfi, fichero, tarjeta );


La otra solución es creando memoria dinámica, como lo has hecho, pero esto
supone que la función NO puede liberar tal memoria, porque no hemos
terminado de usarla. Esto obliga al código que invocó a
'LoadCardNumberInfo()' a responsabilizarse por la liberación de la memoria
dinámica de la estructura. Esto es,

PINDEX LoadCardNumberInfo( FILE *fileptr, int card_number )
{
  pindex = malloc( sizeof (CARDFILEINDEX) );
  ...
  return pindex;
}

Y en el código invocador, escribiríamos,

PINDEX pi = LoadCardNumberInfo( fichero, tarjeta );
...
free( pi );


Una tercera solución es simplemente retornar una estructura. Esto es,

CARDFILEINDEX LoadCardNumberInfo( FILE *fileptr, int card_number )
{
  CARDFILEINDEX index;
  ...
  return index;
}

En el código que invoca a 'LoadCardNumberInfo()', escribiríamos,

CARDFILEINDEX cfi;

cfi = LoadCardNumberInfo( fichero, tarjeta );

El problema es que la estructura, 'CARDFILEINDEX', ocupa varios bytes, por
lo que hay un coste algo más elevado cada vez que invoques la función,
'LoadCardNumberInfo()'.



Por último, aconsejo invocar 'GetFileType()' una sola vez, en lugar de
hasta tres veces. Esto es,

int type = GetFileType( fileptr );

if( 0 == n )
  fseek( fileptr, 5, SEEK_SET );
else if( n == 1 || 2 == n)
  fseek( fileptr, 9, SEEK_SET) ;
else
  return NULL;

O puedes usar un 'switch/case',

switch( GetFileType( fileptr ) )
{
case 0:
  fseek( fileptr, 5, SEEK_SET );
  break;

case 1:
case 2:
  fseek( fileptr, 9, SEEK_SET) ;
  break;

default:
  return NULL;
}


Espero que esto te aclare las dudas.

Steven


2017-12-18 3:06 GMT-05:00 Personal <santiago230792 en gmail.com>:

> Estimados docentes de C con Clase:
>
> Estuve un tiempo sin seguir con las prácticas del curso de C++ y
> recientemente regresé luego de hacerme un tiempo. Para hacer algo más
> real, decidí comenzar un proyecto más "real" y práctico, para lo cual
> elegí crear una pequeña biblioteca para leer un formato de archivo que
> no sé si tiene una implementación de código abierto como tal, de forma
> que se pudiera reutilizar de forma libre
> (y con licencia libre) para que otras aplicaciones pudieran importar
> datos de este formato, etc.  Mi idea era la de crear una biblioteca
> independiente de la plataforma y dentro de lo posible, sin dependencias
> adicionales, solo requiriendo al menos una versión reciente de las
> bibliotecas de C, y al mismo tiempo seguir aprendiendo en el camino.
> Aclaro que estoy programándola en C para que sea útil tanto en C como en
> C++.
>
> El formato de archivo es el de CARDFILE, una aplicación del antiguo
> Windows 3.11. El formato de archivo no ha sido del todo bien
> documentado, pero algunas especificaciones están en:
> *
> https://support.microsoft.com/en-us/help/99340/windows-3-1-
> card-file-format
> * http://donaldkenney.x10.mx/CARDFILE.HTM#MGC
> *
> https://groups.google.com/forum/#!searchin/comp.windows.
> ms/cardfile;context-place=forum/comp.windows.ms
> * https://en.wikipedia.org/wiki/Cardfile
>
> Este formato es un archivo binario de extensión CRD con tres versiones,
> que se las puede identificar por sus números mágicos: MGC, RRG y DKO. El
> primero fue el formato inicial, el segundo añadió soporte para objetos
> OLE (que se pueden manipular mediante el API de Windows) y el tercero
> habría añadido soporte para Unicode 16 bits.
>
> De forma gráfica, se trata de un archivo que contiene tarjetas o cards,
> en las que se puede guardar información personal al estilo de un
> fichero,  conteniendo varias tarjetas con texto, mapas de bits, objetos
> OLE cada una.
>
> Un archivo CRD se caracteriza por contener tres bloques: (1) un
> encabezado o header, (2) un índice o index, y (3) los datos de las
> tarjetas señaladas en el índice.
> -------
> (1) El encabezado se caracteriza por contener dos o tres sub-bloques
> dependiendo de la implementación, con al menos un "número mágico" y un
> "número de cartas".
>
> (a) El del formato MGC es así:
> [número mágico (3 bytes)="MGC"] [número de tarjetas (2 bytes, little
> endian)] = 5 bytes
>
> (b) Los formatos RRG y DKO serían así:
> [número mágico (3 bytes)="RRG" o "DKO"] [último id de objeto (4 bytes,
> little endian)][número de tarjetas (2 bytes, en little endian)] = 9 bytes
>
> Al "ultimo id de objeto" no le veo demasiada utilidad por el momento. El
> numero de
> tarjetas sí es un dato importante para acceder al resto del archivo.
> -----
> (2) El índice comienza una vez termina el encabezado, la distribución de
> bytes es común a todos los formatos de CRD, y puede repetirse la misma
> estructura tantas veces como tarjetas haya en el archivo:
>
> (a) [reservado (6 bytes)= 0x000000]
> (b) [posición en el archivo de los datos asociados a esta entrada de
> índice (4 bytes)]
> (c) [flag inicial (1 byte) = 0x00]
> (d) [título del índice de la tarjeta (40 bytes) = cadena de texto]
> (e) [flag final  (1 byte) = 0x00]
>
> Por ejemplo, si hay dos tarjetas, tendríamos:
> [[ENCABEZADO:...]]
> [[ÍNDICE:
>  [reserv.] [pos. datos 1=0x39] [flag] [titulo indice 1] [flag final]
>  [reserv.] [pos. datos 2=0xnn] [flag] [titulo indice 2] [flag final]
> ]]
> [[DATOS:
>   0x39->...
>   0xnn->...
> ]]
>
> -----
> (3) La sección de datos es más compleja y su implementación depende de la
> versión de archivo CRD. La más simple es la de los MGC, con la cual
> estaba empezando a trabajar.
>
> Más o menos se compone así para los MGC:
>
> (a) [Tamaño de objeto bmp en little endian] 0x0000 (no hay objeto) u otro
> valor si hay uno, del peso indicado, en little endian
> (b) [OPCIONAL-objeto:
>          (b.1) [ancho=2 bytes]
>          (b.2) [alto=2 bytes]
>          (b.3) [x=2 bytes]
>          (b.4) [y=2 bytes]
>          (b.5) [datos (tamaño en bytes indicado en "(a)" )]
> (c) [Tamaño de texto=2 bytes little endian]
> (d) [Texto=440 bytes]
>
> En los RRG es así
> (a) [Flag de objeto bmp en little endian] 0x0000 (no hay objeto) o
> 0x0001 (hay un objeto) en little endian
> (b) [OPCIONAL-Muchos flags del objeto OLE que no enumeraré aquí...]
> (c) [Tamaño de texto]
> (d) [Texto=440 bytes]
> ---------------------
>
> En cuanto a la implementación, recién estaba empezando, y estaba
> haciendo una función que retornaba un puntero a una estructura del
> índice para poder obtener los datos del índice, es decir, el título del
> índice y la ubicación de los datos dentro del archivo:
>
> PINDEX LoadCardNumberInfo (FILE *fileptr, int card_number);
>
> PINDEX es un puntero a la estructura que hace referencia a la sección
> índice del archivo.
>
> Pero por alguna razón la función no está trabajando como debería y me da
> un error al ejecutar. He intentado detectar con el depurador cómo
> modificar este comportamiento, pero no tuve éxito.
>
> La función trabaja de esta forma:
>
> 1. Externamente se abre el archivo. Dentro de la función se declara una
> instancia del puntero a la estructura del índice.
> 2. Consulta la versión de archivo CRD para determinar cuánto debe
> moverse el "cursor" con fseek, o retorna un puntero nulo en caso de ser
> un tipo de archivo desconocido. Esto se debe a que como ya expliqué más
> arriba, el índice comienza en posiciones distintas si se trata de un
> MGC, o en otro caso, de los RRG y DKO.
> 3. Reserva memoria dinámica en caso de que (2) no haya tenido error.
> 4. Se mueve a la posición indicada en (2).
> 5. Abre un bucle for para recorrer secuencialmente la sección de índices:
>     a. Evita el campo de 6 bytes reservados, que no nos es útil, hasta
> el comienzo del campo de <posición datos>.
>     b. Lee <posición datos> y lo convierte a big endian para poder
> trabajar con él. Si no lo hice mal, este dato se guarda dentro de la
> instancia de la estructura. No sé si en realidad debería guardar el dato
> en una variable temporal.
>     c. Evita el flag de comienzo del texto de la entrada de índice.
>     d. Lee el texto del índice. De nuevo, no sé si no lo hice mal, este
> dato se guarda dentro de la instancia de la estructura. No sé si en
> realidad debería guardar el dato en una variable temporal.
>     e. Evita el flag de cierre del texto de la entrada del índice, y se
> repite el bucle hasta llegado el número de índice indicado.
> 6. Se mueve el cursor al principio del archivo y libera memoria (si
> corresponde).
> 7. Retorna un puntero a la estructura con los datos recogidos, para
> trabajar de forma externa a la función.
>
> ¿Podría Ud. ver el código y  ver en qué falla mi implementación, que
> luego de haberlo analizado no logro encontrar una respuesta?
>
> Adjunto en caso de ser necesario el código fuente actual y unos archivos
> de ejemplo para probar en la línea de comandos con una implementación de
> un programa de ejemplo que utiliza la biblioteca como base. Para leer
> los datos binarios de los archivos CRD utilicé el editor hexadecimal
> FRHED, aunque supongo que cualquier otro similar será igualmente útil.
>
> Muchas gracias.
> Saludos
>
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20171219/2b1719f7/attachment.html>


Más información sobre la lista de distribución Cconclase