Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 300052b921 | |||
| f898080e47 |
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,12 @@
|
||||
# Capítulo 13 — Archivos
|
||||
# Capítulo 14 — Archivos
|
||||
|
||||
> Capítulo intermedio/avanzado. Se apoya en lo aprendido sobre arreglos (`06`), punteros (`07`),
|
||||
> `struct` (`08`), memoria dinámica (`09-memoria-dinamica`) y arenas (`12-arenas`).
|
||||
> Se recomienda leerlo después de tener claros `malloc`, `free`, el uso de punteros y
|
||||
> la idea de reservar memoria en bloques (arenas).
|
||||
> `struct` (`08`), memoria dinámica (`09-memoria-dinamica`), entrada/salida estándar
|
||||
> (`13-entrada-salida-estandar`) y arenas (`12-arenas`).
|
||||
> Se recomienda leerlo después de tener claros `malloc`, `free`, el uso de punteros,
|
||||
> el manejo de `stdin`/`stdout`/`stderr` y la idea de reservar memoria en bloques (arenas).
|
||||
|
||||
## 13.1 ¿Por qué leer y escribir archivos?
|
||||
## 14.1 ¿Por qué leer y escribir archivos?
|
||||
|
||||
Hasta ahora, nuestros programas intercambiaban información únicamente a través de la consola
|
||||
(entrada por teclado y salida por pantalla). Esto está bien para ejercicios cortos, pero
|
||||
@@ -16,7 +17,7 @@ archivos compactados.
|
||||
Un archivo nos permite guardar información en disco para usarla más tarde, compartirla entre
|
||||
programas o procesarla por lotes. El desafío es hacerlo de forma **clara, segura y correcta**.
|
||||
|
||||
### 13.1.1 Texto vs Binario
|
||||
### 14.1.1 Texto vs Binario
|
||||
|
||||
En C, los archivos se dividen en dos grandes categorías:
|
||||
|
||||
@@ -31,7 +32,7 @@ binario como si fuera texto corrompe su estructura. Por eso, al abrir un archivo
|
||||
usamos modos distintos: `r`, `w`, `a` para texto y `rb`, `wb`, `ab` (más `+` cuando corresponde)
|
||||
para binario.
|
||||
|
||||
### 13.1.2 Recursos: abrir y cerrar
|
||||
### 14.1.2 Recursos: abrir y cerrar
|
||||
|
||||
Todo archivo abierto consume un recurso del sistema. Por eso, **siempre hay que cerrarlo**
|
||||
cuando terminamos de usarlo. El par básico es:
|
||||
@@ -46,13 +47,13 @@ Un error común es olvidar `fclose()` o no cerrarlo en todos los caminos posible
|
||||
si ocurre un error a mitad del proceso). Más adelante veremos cómo mitigar esto usando
|
||||
distintas estrategias de gestión de memoria/buffers.
|
||||
|
||||
## 13.2 Lectura y escritura de archivos de texto
|
||||
## 14.2 Lectura y escritura de archivos de texto
|
||||
|
||||
La librería estándar de C (`stdio.h`) ofrece un conjunto de funciones para trabajar con archivos.
|
||||
Antes de usarlas, veamos **cada una**: cómo se llama, qué recibe y qué devuelve. Casi todas giran
|
||||
en torno al tipo `FILE *`, que es el **manejador** (handle) del archivo abierto.
|
||||
|
||||
### 13.2.1 Modos de apertura
|
||||
### 14.2.1 Modos de apertura
|
||||
|
||||
`fopen` recibe la ruta y un **modo** que decide qué se puede hacer con el archivo:
|
||||
|
||||
@@ -78,16 +79,16 @@ Agregando una `b` (`"rb"`, `"wb"`, `"ab"`, ...) se abre en **modo binario**.
|
||||
>
|
||||
> Esa es toda la diferencia (y solo importa en Windows; en Linux/macOS no hay traducción). Por eso los
|
||||
> archivos cuyos bytes deben leerse **exactos** —imágenes, audio, o la cabecera ASCII de un PPM
|
||||
> mezclada con píxeles— se abren con `"b"`. Ojo: el `\n` de la cabecera PPM del ejemplo (13.5) es un
|
||||
> mezclada con píxeles— se abren con `"b"`. Ojo: el `\n` de la cabecera PPM del ejemplo (14.5) es un
|
||||
> **byte real del archivo** (`0x0A`), no una traducción del modo texto.
|
||||
|
||||
### 13.2.2 Referencia: funciones de texto
|
||||
### 14.2.2 Referencia: funciones de texto
|
||||
|
||||
#### `fopen` — abrir un archivo
|
||||
```c
|
||||
FILE *fopen(const char *path, const char *mode);
|
||||
```
|
||||
- **Recibe:** `path`, la ruta del archivo; `mode`, el modo de apertura (ver 13.2.1).
|
||||
- **Recibe:** `path`, la ruta del archivo; `mode`, el modo de apertura (ver 14.2.1).
|
||||
- **Devuelve:** un `FILE *` (el manejador del archivo abierto) o `NULL` si no se pudo abrir.
|
||||
- **Ojo:** hay que verificar siempre `NULL` antes de usar el manejador.
|
||||
|
||||
@@ -190,7 +191,7 @@ Y leído paso a paso:
|
||||
> Fijate en el gráfico: el cursor termina en la posición 9, **justo antes del `\n`**. `fscanf` consume
|
||||
> todos los dígitos de cada número, pero **nunca** el `\n` que sigue al último: ese separador queda
|
||||
> **sin leer**. Si tu programa necesita leer lo que viene inmediatamente después, tenés que "comerte"
|
||||
> ese separador con `fgetc()`. Es exactamente lo que hace el ejemplo de la sección 13.5.2 antes de leer
|
||||
> ese separador con `fgetc()`. Es exactamente lo que hace el ejemplo de la sección 14.5.2 antes de leer
|
||||
> los píxeles.
|
||||
|
||||
#### `feof` — ¿se llegó al final?
|
||||
@@ -229,7 +230,7 @@ int tolower(int c);
|
||||
> `printf`, `scanf`, `malloc`, `free` y `sizeof` ya se vieron en capítulos anteriores; acá nos
|
||||
> concentramos en lo específico de archivos.
|
||||
|
||||
### 13.2.3 Ejemplo: leer un archivo carácter por carácter
|
||||
### 14.2.3 Ejemplo: leer un archivo carácter por carácter
|
||||
|
||||
Con `fgetc()` leés **un byte por vez**. El valor de retorno es un `int`, no un `char`, para que
|
||||
pueda distinguirse el valor `EOF` (fin de archivo, normalmente `-1`). Este es el patrón clásico
|
||||
@@ -265,7 +266,7 @@ Observá tres detalles que se repiten en **todos** los programas con archivos:
|
||||
2. El bucle corta cuando `fgetc()` devuelve `EOF`.
|
||||
3. Se cierran **los dos** archivos, en orden inverso al que se abrieron.
|
||||
|
||||
### 13.2.4 Ejemplo: leer línea por línea con `fgets`
|
||||
### 14.2.4 Ejemplo: leer línea por línea con `fgets`
|
||||
|
||||
Para trabajar línea a línea, `fgets()` es más cómodo que `fgetc()`. Lee como máximo `n - 1`
|
||||
caracteres, o hasta encontrar un `\n` (que **deja incluido** en el buffer), o hasta el fin del
|
||||
@@ -297,7 +298,7 @@ int main(void) {
|
||||
> buffer, `fgets()` la entrega **cortada** en varios pedazos. Para este capítulo, asumimos líneas
|
||||
> razonables.
|
||||
|
||||
### 13.2.5 Ejemplo: escribir con formato (`fprintf`)
|
||||
### 14.2.5 Ejemplo: escribir con formato (`fprintf`)
|
||||
|
||||
`fprintf()` es a un archivo lo que `printf()` es a la pantalla: acepta el mismo formato.
|
||||
|
||||
@@ -324,15 +325,15 @@ int main(void) {
|
||||
Con modo `"w"` el archivo se **trunca** (si ya existía, se borra su contenido). Para **agregar**
|
||||
al final sin borrar lo anterior, se usa el modo `"a"`.
|
||||
|
||||
## 13.3 Ejercicios: archivos de texto
|
||||
## 14.3 Ejercicios: archivos de texto
|
||||
|
||||
> **Regla fundamental:** ningún ejercicio incluye código de solución. Solo se describe el problema,
|
||||
> entrada/salida, conceptos y criterios de aceptación. Se permiten fragmentos de entrada/salida
|
||||
> esperada como ejemplos.
|
||||
|
||||
Estos ejercicios trabajan sobre lo visto en la sección 13.2: `fgetc`, `fgets`, `fprintf` y `feof`.
|
||||
Estos ejercicios trabajan sobre lo visto en la sección 14.2: `fgetc`, `fgets`, `fprintf` y `feof`.
|
||||
|
||||
### Ejercicio 13.1 — Contador de líneas y caracteres (texto, básico)
|
||||
### Ejercicio 14.1 — Contador de líneas y caracteres (texto, básico)
|
||||
|
||||
**Conceptos** · `FILE*`, `fopen`, `fclose`, `fgetc`, `feof`
|
||||
|
||||
@@ -375,7 +376,7 @@ incrementar al encontrar `\n`). Siempre validar que el archivo se abrió correct
|
||||
- [ ] Cierra el archivo con `fclose()` antes de terminar.
|
||||
- [ ] Muestra salida con formato claro.
|
||||
|
||||
### Ejercicio 13.2 — Copia de archivo de texto (texto, básico)
|
||||
### Ejercicio 14.2 — Copia de archivo de texto (texto, básico)
|
||||
|
||||
**Conceptos** · `FILE*`, `fopen`, `fclose`, `fgetc`, `fputc`
|
||||
|
||||
@@ -413,7 +414,7 @@ y escribir con `fputc()`. Verificar aperturas y cierres. No modificar el conteni
|
||||
- [ ] Reporta errores de forma clara.
|
||||
- [ ] Cierra ambos archivos.
|
||||
|
||||
### Ejercicio 13.3 — Leer líneas y guardar filtradas (texto, intermedio)
|
||||
### Ejercicio 14.3 — Leer líneas y guardar filtradas (texto, intermedio)
|
||||
|
||||
**Conceptos** · `fgets`, buffers, cadenas, condicionales
|
||||
|
||||
@@ -463,7 +464,7 @@ Abrir archivos en modo texto.
|
||||
- [ ] Informa cantidad de líneas copiadas.
|
||||
- [ ] Maneja errores de apertura correctamente.
|
||||
|
||||
## 13.4 Lectura y escritura de archivos binarios
|
||||
## 14.4 Lectura y escritura de archivos binarios
|
||||
|
||||
Cuando trabajamos con datos estructurados o con formatos como imágenes, necesitamos leer/escribir
|
||||
**bytes exactos**, sin que el sistema modifique nada (ni convierta finales de línea). Para eso
|
||||
@@ -472,10 +473,10 @@ usamos `fread()` y `fwrite()`, junto con funciones para ubicarse dentro del arch
|
||||
> **Antes de leer, mirá.** Un archivo binario no se puede abrir con un editor de texto: vas a ver
|
||||
> basura, y encima el editor puede corromperlo. Para *ver* los bytes sin instalar nada, usá
|
||||
> **ImHex Web** (<https://web.imhex.werwolv.net/>): un editor hexadecimal que corre entero en el
|
||||
> navegador. Abrí ahí el BMP de la sección 13.8.6 o el PPM de la 13.5.1, ubicá los offsets y
|
||||
> navegador. Abrí ahí el BMP de la sección 14.8.6 o el PPM de la 14.5.1, ubicá los offsets y
|
||||
> contrastá campo por campo lo que muestra la herramienta con lo que escribe tu programa.
|
||||
|
||||
### 13.4.1 Referencia: funciones binarias
|
||||
### 14.4.1 Referencia: funciones binarias
|
||||
|
||||
#### `fread` — leer un bloque
|
||||
```c
|
||||
@@ -530,7 +531,7 @@ dependiendo del formato y de la plataforma. En este capítulo nos enfocamos en *
|
||||
la estructura byte a byte del archivo** y leerlo correctamente según su especificación,
|
||||
sin asumir conversiones mágicas.
|
||||
|
||||
### 13.4.2 Ejemplo: averiguar el tamaño de un archivo
|
||||
### 14.4.2 Ejemplo: averiguar el tamaño de un archivo
|
||||
|
||||
Antes de leer un archivo binario completo conviene saber **cuántos bytes tiene**. El truco es
|
||||
moverse al final con `fseek()`, preguntar la posición con `ftell()` y volver al principio con
|
||||
@@ -560,7 +561,7 @@ int main(void) {
|
||||
> `long` alcanza para archivos de tamaño normal. Para archivos gigantes existen `fseeko()` y
|
||||
> `ftello()` (con `off_t`), pero no hacen falta en este capítulo.
|
||||
|
||||
### 13.4.3 Ejemplo: leer el archivo completo a memoria
|
||||
### 14.4.3 Ejemplo: leer el archivo completo a memoria
|
||||
|
||||
El patrón es: medir el tamaño, reservar un bloque con `malloc()`, leer todo de una sola vez con
|
||||
`fread()` y **siempre** liberar al terminar:
|
||||
@@ -599,7 +600,7 @@ int main(void) {
|
||||
> `fread()` devuelve **cuántos elementos** leyó realmente. Puede leer menos de lo pedido si el
|
||||
> archivo se acorta o si ocurre un error, así que conviene comparar con lo esperado.
|
||||
|
||||
### 13.4.4 Ejemplo: leer una cabecera fija a una `struct`
|
||||
### 14.4.4 Ejemplo: leer una cabecera fija a una `struct`
|
||||
|
||||
Los archivos binarios suelen empezar con una cabecera de tamaño fijo. Se puede leer de una sola
|
||||
vez dentro de una `struct` que tenga **exactamente** el mismo diseño de bytes:
|
||||
@@ -640,14 +641,14 @@ int main(void) {
|
||||
> `struct` en memoria puede **no coincidir** con el del archivo. En esos casos conviene leer los
|
||||
> campos de a uno con `fread()` a variables sueltas, en lugar de a una `struct` entera.
|
||||
|
||||
## 13.5 Ejemplo guiado: otro formato binario — PPM (Netpbm)
|
||||
## 14.5 Ejemplo guiado: otro formato binario — PPM (Netpbm)
|
||||
|
||||
Antes del desafío de BMP, practiquemos con un formato binario **más simple todavía**: el **PPM**
|
||||
(Portable PixMap), uno de los formatos **Netpbm**. Su virtud didáctica es que su cabecera es
|
||||
**texto plano** y sus datos son una **matriz de colores sin compresión ni padding**, así que
|
||||
separa muy bien "leer la cabecera" de "leer los píxeles".
|
||||
|
||||
### 13.5.1 Descripción del formato PPM (variante P6)
|
||||
### 14.5.1 Descripción del formato PPM (variante P6)
|
||||
|
||||
Un archivo `.ppm` binario (variante **P6**) tiene esta estructura:
|
||||
|
||||
@@ -675,7 +676,7 @@ Algunas diferencias con BMP que conviene notar:
|
||||
| Orden de las filas | Arriba → abajo | Abajo → arriba |
|
||||
| Relleno por fila (padding) | No tiene | Múltiplo de 4 bytes |
|
||||
|
||||
### 13.5.2 Cómo leerlo
|
||||
### 14.5.2 Cómo leerlo
|
||||
|
||||
El siguiente programa lee la cabecera con `fscanf()`/`fgetc()` (son texto) y luego los píxeles con
|
||||
`fread()` (son binario). El truco clave está en el **paso 3**: después de `maxval` hay
|
||||
@@ -702,7 +703,7 @@ int main(void) {
|
||||
}
|
||||
|
||||
/* 2. ancho, alto y valor máximo (son números en ASCII).
|
||||
* Detalle de fscanf: ver la sección 13.2.2. */
|
||||
* Detalle de fscanf: ver la sección 14.2.2. */
|
||||
int width, height, maxval;
|
||||
if (fscanf(fp, "%d %d %d", &width, &height, &maxval) != 3) {
|
||||
fprintf(stderr, "cabecera PPM inválida\n");
|
||||
@@ -749,14 +750,14 @@ int main(void) {
|
||||
> mismas que necesitarás para BMP: leer y validar la firma, extraer dimensiones, consumir el
|
||||
> separador exacto entre cabecera y datos, y mapear `(x, y)` a un índice del buffer. La diferencia
|
||||
> es que BMP agrega **orden invertido de filas** y **relleno (padding) por fila**, que veremos en la
|
||||
> sección 13.8.
|
||||
> sección 14.8.
|
||||
|
||||
## 13.6 Gestión de memoria: `malloc/free` vs Arenas
|
||||
## 14.6 Gestión de memoria: `malloc/free` vs Arenas
|
||||
|
||||
Al leer archivos, especialmente archivos binarios de tamaño variable o con estructuras anidadas,
|
||||
necesitamos almacenar lo leído en memoria. Tenemos dos enfoques principales:
|
||||
|
||||
### 13.6.1 Con `malloc` y `free`
|
||||
### 14.6.1 Con `malloc` y `free`
|
||||
|
||||
- Reservamos exactamente lo que necesitamos (`malloc` del tamaño leído).
|
||||
- Liberamos cada bloque cuando ya no lo usamos (`free`).
|
||||
@@ -764,7 +765,7 @@ necesitamos almacenar lo leído en memoria. Tenemos dos enfoques principales:
|
||||
- **Desventaja:** si leemos muchos bloques o estructuras pequeñas, debemos rastrear cada `free`.
|
||||
También complica liberar todo ante un error a mitad del proceso.
|
||||
|
||||
### 13.6.2 Con arenas (bump allocator)
|
||||
### 14.6.2 Con arenas (bump allocator)
|
||||
|
||||
Recordando el concepto del Capítulo 12: reservamos **un bloque grande** una sola vez,
|
||||
avanzamos un cursor para repartir memoria y **liberamos todo junto** (reiniciamos cursor o
|
||||
@@ -782,7 +783,7 @@ Aplicado a lectura de archivos:
|
||||
a **leer archivos correctamente** y que puedas implementar la lectura **usando malloc/free**
|
||||
y también **usando arenas**, entendiendo cuándo conviene cada uno.
|
||||
|
||||
## 13.7 Errores y robustez
|
||||
## 14.7 Errores y robustez
|
||||
|
||||
Al trabajar con archivos, hay que considerar fallas posibles:
|
||||
|
||||
@@ -800,13 +801,13 @@ Al trabajar con archivos, hay que considerar fallas posibles:
|
||||
4. Cerrar el archivo en todos los caminos (incluso ante errores). Esto puede hacerse con cuidado
|
||||
o estructurando el código para asegurar el cierre.
|
||||
|
||||
## 13.8 El formato BMP: documentación de referencia
|
||||
## 14.8 El formato BMP: documentación de referencia
|
||||
|
||||
Antes del desafío final, necesitamos entender el formato que vamos a interpretar: **BMP**
|
||||
(Windows Bitmap). Lo elegimos porque es uno de los formatos de imagen **más simples** de leer:
|
||||
guarda los píxeles **sin compresión** y documenta su estructura con cabeceras bien definidas.
|
||||
|
||||
### 13.8.1 Estructura general de un BMP
|
||||
### 14.8.1 Estructura general de un BMP
|
||||
|
||||
Un archivo `.bmp` se compone de estas partes, en este orden:
|
||||
|
||||
@@ -815,7 +816,7 @@ Un archivo `.bmp` se compone de estas partes, en este orden:
|
||||
3. **Paleta de colores** (opcional): solo para profundidades de 1, 4 u 8 bits.
|
||||
4. **Datos de píxeles** (pixel data): la matriz de píxeles.
|
||||
|
||||
### 13.8.2 BITMAPFILEHEADER (14 bytes)
|
||||
### 14.8.2 BITMAPFILEHEADER (14 bytes)
|
||||
|
||||
| Offset | Tamaño | Campo | Descripción |
|
||||
|---|---|---|---|
|
||||
@@ -825,7 +826,7 @@ Un archivo `.bmp` se compone de estas partes, en este orden:
|
||||
| 8 | 2 | `bfReserved2` | Reservado, debe ser 0. |
|
||||
| 10 | 4 | `bfOffBits` | Offset en bytes donde comienzan los datos de píxeles. |
|
||||
|
||||
### 13.8.3 BITMAPINFOHEADER (40 bytes, versión más común)
|
||||
### 14.8.3 BITMAPINFOHEADER (40 bytes, versión más común)
|
||||
|
||||
| Offset | Tamaño | Campo | Descripción |
|
||||
|---|---|---|---|
|
||||
@@ -844,7 +845,7 @@ Un archivo `.bmp` se compone de estas partes, en este orden:
|
||||
**Resumen:** desde el offset 14 hasta el 53 (40 bytes) está toda la información que
|
||||
necesitamos para saber cómo leer los píxeles.
|
||||
|
||||
### 13.8.4 Datos de píxeles
|
||||
### 14.8.4 Datos de píxeles
|
||||
|
||||
Los píxeles comienzan en el offset indicado por `bfOffBits` (campo del archivo, offset 10).
|
||||
|
||||
@@ -867,17 +868,17 @@ bytesPorFila = ((biWidth * 3 + 3) / 4) * 4
|
||||
|
||||
Las filas reales se leen desde el final hacia el principio si la imagen es bottom-up.
|
||||
|
||||
### 13.8.5 Paleta (solo para 1, 4 u 8 bpp)
|
||||
### 14.8.5 Paleta (solo para 1, 4 u 8 bpp)
|
||||
|
||||
Para 8 bits por píxel, cada píxel es 1 byte que es un **índice** a una tabla de 256 colores
|
||||
(paleta). Cada entrada de la paleta ocupa 4 bytes: `B`, `G`, `R`, reservado (0).
|
||||
La paleta comienza inmediatamente después de la cabecera de bits (offset `14 + biSize`).
|
||||
|
||||
### 13.8.6 Anatomía de un BMP real: ejemplo byte a byte
|
||||
### 14.8.6 Anatomía de un BMP real: ejemplo byte a byte
|
||||
|
||||
Las tablas de arriba describen el formato en abstracto. Ahora veamos un **BMP real**, chiquito
|
||||
a propósito (5×3 píxeles, 102 bytes), para seguir cada campo sobre los bytes mismos. Es el
|
||||
mismo archivo que usamos más adelante para verificar el Ejercicio 13.8.
|
||||
mismo archivo que usamos más adelante para verificar el Ejercicio 14.8.
|
||||
|
||||
<img width="150" alt="Render de ejemplo-bmp-5x3.bmp: grilla de 5×3 píxeles con los bordes dibujados en negro"
|
||||
style="image-rendering: pixelated;"
|
||||
@@ -957,7 +958,7 @@ buffer copiá la fila `i` del archivo a la fila `height - 1 - i` de la imagen.
|
||||
> coordenada (2, 1) —columna 2, fila 1— y es **verde**: `RGB(34, 177, 76)`. Es una forma
|
||||
> rapidísima de saber si tu programa leyó bien las cabeceras y el padding.
|
||||
|
||||
### 13.8.7 Cómo leer un BMP (flujo sugerido)
|
||||
### 14.8.7 Cómo leer un BMP (flujo sugerido)
|
||||
|
||||
1. Abrir el archivo en binario (`rb`).
|
||||
2. Leer los 14 bytes del **BITMAPFILEHEADER**.
|
||||
@@ -973,7 +974,7 @@ buffer copiá la fila `i` del archivo a la fila `height - 1 - i` de la imagen.
|
||||
> el byte menos significativo va primero. Leerlos con `fread` en un `uint32_t` funciona bien en
|
||||
> máquinas little-endian (x86/x64).
|
||||
|
||||
## 13.9 Mostrar la imagen en pantalla (opcional): SDL2
|
||||
## 14.9 Mostrar la imagen en pantalla (opcional): SDL2
|
||||
|
||||
Hasta acá todo el trabajo fue **leer e interpretar** bytes. Un objetivo opcional y muy motivador es
|
||||
**mostrar la imagen** en una ventana. C no trae esto en su biblioteca estándar: dibujar ventanas es
|
||||
@@ -983,7 +984,7 @@ para empezar es **SDL2**.
|
||||
> Esta sección es **opcional** y va más allá del objetivo central del capítulo (leer archivos).
|
||||
> SDL2 es una **dependencia externa**; si tu entorno no la tiene, podés saltearla sin problema.
|
||||
|
||||
### 13.9.1 La idea
|
||||
### 14.9.1 La idea
|
||||
|
||||
Ya tenés los píxeles en memoria, con 3 bytes por píxel. SDL2 ofrece una función que **envuelve un
|
||||
buffer de píxeles** en una superficie dibujable, sin copiar los datos:
|
||||
@@ -1012,7 +1013,7 @@ Si en cambio guardaste los píxeles en el orden `B, G, R` tal cual vienen en BMP
|
||||
**intercambian** entre rojo y azul. Este es el error más común: colores correctos pero con rojo y
|
||||
azul cambiados.
|
||||
|
||||
### 13.9.2 Programa mínimo de visualización
|
||||
### 14.9.2 Programa mínimo de visualización
|
||||
|
||||
Este programa asume que ya cargaste la imagen en `pixels` (un buffer `width * height * 3` en orden
|
||||
`R, G, B`, con la fila `0` **arriba**). Muestra la ventana hasta que la cierres o presiones una
|
||||
@@ -1059,14 +1060,14 @@ int main(void) {
|
||||
}
|
||||
```
|
||||
|
||||
### 13.9.3 El detalle de las filas: BMP es bottom-up
|
||||
### 14.9.3 El detalle de las filas: BMP es bottom-up
|
||||
|
||||
SDL espera la **fila 0 arriba**. BMP, en cambio, guarda la imagen **de abajo hacia arriba**. Si
|
||||
volcás los píxeles tal como los leíste, la imagen va a aparecer **invertida verticalmente**.
|
||||
La solución es copiar cada fila a su posición espejada (`fila destino = height - 1 - fila origen`)
|
||||
al momento de cargar el buffer.
|
||||
|
||||
### 13.9.4 Compilar y enlazar
|
||||
### 14.9.4 Compilar y enlazar
|
||||
|
||||
SDL2 se enlaza como cualquier biblioteca externa. Con `gcc` y la utilidad `sdl2-config`:
|
||||
|
||||
@@ -1082,14 +1083,14 @@ distribuciones Linux, el paquete suele llamarse `libsdl2-dev`.
|
||||
> explícito del capítulo. Esta sección es la excepción deliberada y por eso queda marcada como
|
||||
> opcional.
|
||||
|
||||
## 13.10 Ejercicios: archivos binarios
|
||||
## 14.10 Ejercicios: archivos binarios
|
||||
|
||||
Estos ejercicios ponen a prueba la segunda mitad del capítulo: archivos binarios con `fread` y
|
||||
`fwrite` (sección 13.4), el formato PPM (13.5), arenas (13.6), errores (13.7) y el formato BMP
|
||||
(13.8). La regla fundamental de la sección 13.3 sigue en pie: **ningún ejercicio incluye código
|
||||
`fwrite` (sección 14.4), el formato PPM (14.5), arenas (14.6), errores (14.7) y el formato BMP
|
||||
(14.8). La regla fundamental de la sección 14.3 sigue en pie: **ningún ejercicio incluye código
|
||||
de solución**.
|
||||
|
||||
### Ejercicio 13.4 — Lectura binaria con `fread` (binario, intermedio)
|
||||
### Ejercicio 14.4 — Lectura binaria con `fread` (binario, intermedio)
|
||||
|
||||
**Conceptos** · Archivos binarios, `fopen` con `rb`, `fread`, buffers de bytes
|
||||
|
||||
@@ -1126,21 +1127,21 @@ y leer todo con `fread(buf, 1, size, fp)`. Verificar que `fread` leyó lo espera
|
||||
- [ ] Muestra primeros N bytes en formato legible (hex).
|
||||
- [ ] Libera memoria con `free()` y cierra archivo.
|
||||
|
||||
### Ejercicio 13.5 — Lectura binaria usando arena (arenas + binario, intermedio)
|
||||
### Ejercicio 14.5 — Lectura binaria usando arena (arenas + binario, intermedio)
|
||||
|
||||
**Conceptos** · Arenas (bump allocator), lectura binaria, bloques grandes
|
||||
|
||||
**Consigna** · Repetir el Ejercicio 13.4, pero **reservando toda la memoria necesaria desde una arena**
|
||||
**Consigna** · Repetir el Ejercicio 14.4, pero **reservando toda la memoria necesaria desde una arena**
|
||||
en lugar de llamar `malloc` directamente para el buffer completo. El programa debe:
|
||||
- Crear una arena con capacidad suficiente para alojar el contenido completo del archivo
|
||||
(o un bloque razonable si se desea leer por chunks; para este ejercicio, leer completo).
|
||||
- Leer el archivo binario completo dentro de esa arena (usando el espacio de la arena).
|
||||
- Mostrar tamaño y primeros N bytes (igual salida que 13.4).
|
||||
- Mostrar tamaño y primeros N bytes (igual salida que 14.4).
|
||||
- Liberar **todo junto** al final (reiniciar cursor o liberar el bloque de arena completo). **No**
|
||||
hacer `free` por byte/elemento.
|
||||
|
||||
**Entrada** · Ruta del archivo binario y `N`.
|
||||
**Salida** · Igual que Ejercicio 13.4.
|
||||
**Salida** · Igual que Ejercicio 14.4.
|
||||
|
||||
**Identificadores sugeridos** · `arena`, `arenaBlock`, `capacity`, `offset`
|
||||
|
||||
@@ -1157,7 +1158,7 @@ es suficiente para bytes). Leer el archivo completo dentro del espacio asignado
|
||||
- [ ] Libera memoria con **un único `free`** (bloque de arena). No hay frees por partes.
|
||||
- [ ] No hay fugas de memoria ni double-free.
|
||||
|
||||
### Ejercicio 13.6 — Escritura binaria estructurada (binario, avanzado)
|
||||
### Ejercicio 14.6 — Escritura binaria estructurada (binario, avanzado)
|
||||
|
||||
**Conceptos** · `fwrite`, estructuras, archivos binarios, persistencia
|
||||
|
||||
@@ -1195,23 +1196,23 @@ Verificar cantidad leída.
|
||||
- [ ] Maneja memoria con `malloc/free` adecuadamente.
|
||||
- [ ] No corrompe datos al escribir/leer.
|
||||
|
||||
### Ejercicio 13.7 — Persistencia binaria con arena (binario + arenas, avanzado)
|
||||
### Ejercicio 14.7 — Persistencia binaria con arena (binario + arenas, avanzado)
|
||||
|
||||
**Conceptos** · Arenas, `fwrite`/`fread`, buffers desde arena
|
||||
|
||||
**Consigna** · Modificar el Ejercicio 13.6 para que **el buffer de lectura** (donde se cargan
|
||||
**Consigna** · Modificar el Ejercicio 14.6 para que **el buffer de lectura** (donde se cargan
|
||||
los puntos leídos) se reserve **desde una arena**, en lugar de `malloc` directo. También
|
||||
puede reservarse el arreglo original desde arena si se desea. El objetivo es practicar
|
||||
lectura binaria usando espacio de arena.
|
||||
|
||||
**Entrada/Salida** · Igual que Ejercicio 13.6.
|
||||
**Entrada/Salida** · Igual que Ejercicio 14.6.
|
||||
**Criterios de aceptación**
|
||||
- [ ] Buffer de lectura reservado desde arena.
|
||||
- [ ] Lectura con `fread` correcta.
|
||||
- [ ] Verificación OK.
|
||||
- [ ] Liberación con único `free` del bloque de arena (sin frees individuales).
|
||||
|
||||
### Ejercicio 13.8 — (JEFE) Leer un archivo BMP pixel a pixel
|
||||
### Ejercicio 14.8 — (JEFE) Leer un archivo BMP pixel a pixel
|
||||
|
||||
**Conceptos** · Cabeceras binarias (`fread` de estructuras), little-endian, `fseek`, `ftell`,
|
||||
interpretación de píxeles, `malloc/free` y/o arenas (opcional), validación de formato.
|
||||
@@ -1261,12 +1262,12 @@ Salida: Archivo: imagen.bmp
|
||||
- Podés usar una estructura simple para el conteo de colores (p.ej. guardar los 8 colores más
|
||||
frecuentes o un arreglo de conteos).
|
||||
- Opción extra: repetir la lectura usando una **arena** para los buffers de píxeles.
|
||||
- **Archivo de prueba ideal**: el BMP de 5×3 de la sección 13.8.6 (102 bytes, tres filas de
|
||||
- **Archivo de prueba ideal**: el BMP de 5×3 de la sección 14.8.6 (102 bytes, tres filas de
|
||||
color sólido). Es tan chico que verificás todo a mano: `bfOffBits = 54`, `rowSize = 16` (15
|
||||
bytes de color + 1 de relleno), **3 colores × 15 píxeles** y el píxel central (2, 1) debe dar
|
||||
`R=34 G=177 B=76`. El archivo está en `assets/img/ejemplo-bmp-5x3.bmp`.
|
||||
- La documentación del formato está en la sección 13.8. Si querés mostrar la imagen, mirá la
|
||||
sección 13.9 (SDL2, opcional).
|
||||
- La documentación del formato está en la sección 14.8. Si querés mostrar la imagen, mirá la
|
||||
sección 14.9 (SDL2, opcional).
|
||||
|
||||
**Criterios de aceptación**
|
||||
- [ ] Valida la firma `BM` antes de continuar.
|
||||
@@ -1278,4 +1279,4 @@ Salida: Archivo: imagen.bmp
|
||||
- [ ] Maneja archivos inexistentes o corruptos con mensajes de error claros.
|
||||
- [ ] Libera memoria correctamente (con `free` o un solo `free` de la arena).
|
||||
- [ ] (Extra) Implementa la versión con arena y verifica que da el mismo resultado.
|
||||
- [ ] (Extra) Muestra la imagen en una ventana con SDL2 (ver sección 13.9).
|
||||
- [ ] (Extra) Muestra la imagen en una ventana con SDL2 (ver sección 14.9).
|
||||
@@ -1,4 +1,4 @@
|
||||
# Capítulo 14 — Tipos más usados de C
|
||||
# Capítulo 15 — Tipos más usados de C
|
||||
|
||||
> Capítulo avanzado. Se apoya en tipos primitivos (`02`), operadores (`03`), arreglos (`06`),
|
||||
> punteros (`07`) y `struct` (`08`).
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 14.1 ¿Por qué no alcanza con un `int`?
|
||||
## 15.1 ¿Por qué no alcanza con un `int`?
|
||||
|
||||
Un `int` resuelve muchísimos casos, pero **no responde de forma portable** tres preguntas:
|
||||
|
||||
@@ -53,7 +53,7 @@ datos** (valores en bits):
|
||||
|
||||
---
|
||||
|
||||
## 14.2 El mapa de los tipos
|
||||
## 15.2 El mapa de los tipos
|
||||
|
||||
Casi ningún tipo "con nombre" es palabra del lenguaje: son **typedefs** de una cabecera. Estos son
|
||||
los que vas a usar todo el tiempo (tamaño típico en un sistema de 64 bits):
|
||||
@@ -78,7 +78,7 @@ los que vas a usar todo el tiempo (tamaño típico en un sistema de 64 bits):
|
||||
|
||||
---
|
||||
|
||||
## 14.3 `size_t` — los tamaños
|
||||
## 15.3 `size_t` — los tamaños
|
||||
|
||||
**Cabecera:** `<stddef.h>`
|
||||
|
||||
@@ -101,7 +101,7 @@ uses en un `for` inverso (`for (size_t i = n - 1; i >= 0; i--)` es **infinito**)
|
||||
|
||||
---
|
||||
|
||||
## 14.4 `wchar_t` — caracteres anchos
|
||||
## 15.4 `wchar_t` — caracteres anchos
|
||||
|
||||
**Cabecera:** `<stddef.h>`
|
||||
|
||||
@@ -135,7 +135,7 @@ clave no es "agrandar" el tipo, sino **elegir el correcto**. **Se imprimen con `
|
||||
|
||||
---
|
||||
|
||||
## 14.5 `NULL` — el puntero nulo
|
||||
## 15.5 `NULL` — el puntero nulo
|
||||
|
||||
**Cabecera:** `<stddef.h>`
|
||||
|
||||
@@ -148,7 +148,7 @@ conceptual.
|
||||
|
||||
---
|
||||
|
||||
## 14.6 `bool` — verdadero o falso
|
||||
## 15.6 `bool` — verdadero o falso
|
||||
|
||||
**Cabecera:** `<stdbool.h>` (C99; en C23, palabra clave)
|
||||
|
||||
@@ -161,7 +161,7 @@ usarlo:** si necesitás más de dos estados, un `enum` expresa mejor la intenci
|
||||
|
||||
---
|
||||
|
||||
## 14.7 Enteros de ancho exacto
|
||||
## 15.7 Enteros de ancho exacto
|
||||
|
||||
**Cabecera:** `<stdint.h>`
|
||||
|
||||
@@ -205,7 +205,7 @@ printf("%llu\n", (unsigned long long)big);
|
||||
|
||||
---
|
||||
|
||||
## 14.8 ¿Tengo que dejar de usar `int`?
|
||||
## 15.8 ¿Tengo que dejar de usar `int`?
|
||||
|
||||
**No.** Estos tipos **no reemplazan** a `int`: lo **complementan** para casos puntuales. El `int`
|
||||
sigue siendo el tipo por defecto para números enteros comunes.
|
||||
@@ -223,7 +223,7 @@ Pasá a un **tipo preciso** solo cuando **exista un motivo**:
|
||||
- **`wchar_t` / `char32_t`** → un carácter que no entra en un `char`.
|
||||
|
||||
> **Y ojo con el revés:** usar un tipo chico "por las dudas" también trae problemas. `int8_t` llega
|
||||
> hasta 127 (ver la tabla de 13.7): si lo usás para contar, se desborda enseguida. Y encima la
|
||||
> hasta 127 (ver la tabla de 15.7): si lo usás para contar, se desborda enseguida. Y encima la
|
||||
> aritmética se hace en `int` igual.
|
||||
|
||||
```c
|
||||
@@ -255,7 +255,7 @@ int c = a + b; /* 200: la suma se calcula en int, y al achicar se desborda */
|
||||
|
||||
---
|
||||
|
||||
## 14.9 ¿Los tipos chicos ahorran memoria?
|
||||
## 15.9 ¿Los tipos chicos ahorran memoria?
|
||||
|
||||
**Depende de dónde.** Guardar **muchos** valores en tipos chicos sí ahorra memoria; una variable
|
||||
suelta, no.
|
||||
@@ -290,7 +290,7 @@ struct Color2 { int r, g, b; }; /* 12 bytes */
|
||||
|
||||
---
|
||||
|
||||
## 14.10 Errores comunes
|
||||
## 15.10 Errores comunes
|
||||
|
||||
- Comparar un `int` negativo con `sizeof` o `strlen` (el `-1` se vuelve `SIZE_MAX`).
|
||||
- Guardar un tamaño (`sizeof`, tamaño de un archivo) en un `int`.
|
||||
@@ -301,14 +301,14 @@ struct Color2 { int r, g, b; }; /* 12 bytes */
|
||||
|
||||
---
|
||||
|
||||
## 14.11 Ejercicios
|
||||
## 15.11 Ejercicios
|
||||
|
||||
> De **noob** a **pro**, con dificultad creciente. Cada ejercicio declara sus conceptos objetivo;
|
||||
> resolvelos **usando esos conceptos**. Trae un **escenario de prueba** (entrada/salida esperada,
|
||||
> nunca el algoritmo) para que compares lo que imprimís. Compilá con un estándar moderno (C11 o C23)
|
||||
> y avisos activos (`-Wall -Wextra`).
|
||||
|
||||
### Ejercicio 14.1 — Radiografía de tipos
|
||||
### Ejercicio 15.1 — Radiografía de tipos
|
||||
|
||||
**Conceptos** · `sizeof`, `size_t`, `printf` (`%zu`), tipos de `<stddef.h>` y `<stdint.h>`
|
||||
|
||||
@@ -342,7 +342,7 @@ LP64 (Linux/macOS 64-bit) LLP64 (Windows 64-bit)
|
||||
|
||||
---
|
||||
|
||||
### Ejercicio 14.2 — Sumar con `size_t`
|
||||
### Ejercicio 15.2 — Sumar con `size_t`
|
||||
|
||||
**Conceptos** · `size_t`, arreglos, `for`, casos borde
|
||||
|
||||
@@ -369,7 +369,7 @@ count = 1 ; [-5] -> -5
|
||||
|
||||
---
|
||||
|
||||
### Ejercicio 14.3 — El índice que se convierte en gigante
|
||||
### Ejercicio 15.3 — El índice que se convierte en gigante
|
||||
|
||||
**Conceptos** · conversiones con/sin signo, `size_t`, comparaciones
|
||||
|
||||
@@ -395,7 +395,7 @@ explicación: -1 convertido a size_t = SIZE_MAX (18446744073709551615), y SIZE_M
|
||||
|
||||
---
|
||||
|
||||
### Ejercicio 14.4 — Texto que no entra en un byte
|
||||
### Ejercicio 15.4 — Texto que no entra en un byte
|
||||
|
||||
**Conceptos** · `wchar_t`, `L""`, `%lc`, `%ls`, `<uchar.h>`
|
||||
|
||||
@@ -426,7 +426,7 @@ contraste: guardar 'ñ' en un char y usar %c da basura o un byte suelto.
|
||||
|
||||
---
|
||||
|
||||
### Ejercicio 14.5 — El entero de ancho exacto (pro)
|
||||
### Ejercicio 15.5 — El entero de ancho exacto (pro)
|
||||
|
||||
**Conceptos** · `<stdint.h>`, tipos de ancho exacto, portabilidad
|
||||
|
||||
@@ -457,7 +457,7 @@ total = 123456789012345ULL (uint64_t) -> 123456789012345
|
||||
|
||||
---
|
||||
|
||||
## 14.12 Cierre
|
||||
## 15.12 Cierre
|
||||
|
||||
Los tipos de C no son un adorno: son la forma de decir **qué querés representar** y **de qué
|
||||
tamaño**. `size_t` para tamaños, `uintN_t`/`intN_t` para ancho exacto, `bool` para verdades,
|
||||
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user