Compare commits

..

2 Commits

Author SHA1 Message Date
horacio cfaa0ca470 Add PDF documentation for command line arguments 2026-10-13 22:46:30 -03:00
horacio c609be40f8 Add Chapter 15 on Common C Types to exercise book
This chapter covers the most commonly used types in C, including size_t, wchar_t, NULL, bool, and fixed-width integers. It explains the importance of using these types over int for portability and correctness, along with practical examples and exercises to reinforce understanding.
2026-10-13 22:46:22 -03:00
9 changed files with 1610 additions and 110 deletions
+59 -3
View File
@@ -145,7 +145,63 @@ Un ejercicio puede combinar conceptos de niveles anteriores, pero **no debe exig
--- ---
## 7. Lo que está prohibido ## 7. Estilo didáctico al explicar conceptos ("para tontos")
Los capítulos no solo enuncian ejercicios: también **explican** los conceptos que el lector necesita.
Esa explicación sigue un estilo llano, concreto y progresivo —el mismo que se usó en
`book/14-entrada-salida-estandar.md`—, pensado para que el lector **entienda de verdad** y no solo
lea. Estas reglas aplican a **todo capítulo** que explique conceptos.
**Analogía cotidiana primero.** Todo concepto arranca con una comparación del mundo real que el lector
ya domina; recién después aparece el término técnico. Ejemplos del capítulo 14: las tres tuberías
(`stdin`/`stdout`/`stderr`) son "una fábrica"; `getchar` es "sacar caramelos de a uno"; el búfer es
"el villano de la película". La analogía se sostiene durante toda la explicación; no se abandona a la
primera frase.
**Títulos con gancho, no etiquetas.** En vez de "Introducción a `getchar`", el título promete algo
concreto: "`getchar`: el caramelito de a uno". Lo mismo vale para las subsecciones.
**Explicar el POR QUÉ, no solo el qué.** Cada regla llega con su motivo. No alcanza con decir "guardá
en `int`, no en `char`": hay que explicar por qué (tiene que representar los 256 bytes posibles **y**
un valor extra, `EOF`).
**Voz cercana y frases cortas.** Se trata al lector de "vos" (ver sección 6). Párrafos breves, en
presente, sin rodeos. Se permite —y se espera— marcar la idea clave con **negrita** y con MAYÚSCULAS
ocasionales.
**Cómo estructurar un capítulo largo:**
- Dividirlo en **partes** con un **índice** al inicio. La tabla lleva, por cada parte, "la idea en una
frase".
- Después de cada concepto, un **bloque de práctica** con uno o más ejercicios cortos, antes de
avanzar al siguiente concepto.
- Cerrar con un apartado tipo "lo que te llevás": las ideas clave en pocos bullets, y el puente al
capítulo siguiente.
**Recursos que se repiten:**
- **Apodos para las trampas** clásicas: "la trampa N.º 1", "el bug más famoso del principiante", "el
villano de la película".
- **Blockquotes** (`>`) para notas, advertencias y "momentos ajá": "Momento ajá", "Ojo con esto",
"Para guardar", "Truco de laboratorio". En el PDF todas se dibujan con fondo de color (sección 10).
- **Tablas comparativas** para contrastar opciones o señales parecidas (p. ej. `EOF` vs `'\0'` vs
`'\n'`).
- **Diagramas ASCII** para mostrar lo visual: flujos conectados, los dos búferes en serie.
- **Código ilustrativo comentado en lenguaje llano**: cada línea que introduce algo nuevo lleva un
comentario claro y **de varias líneas** que dice exactamente qué hace. Los bloques declaran su
lenguaje en el fence para que `highlight.js` los resalte (sección 10).
- **Escenario de prueba** en cada ejercicio: un bloque `text` con la entrada y la salida esperada,
para que el lector pueda **comprobar** su solución.
**El límite que NO se cruza.** Este estilo permite **código ilustrativo para explicar un concepto**
(una llamada a una función, un esqueleto mínimo, un patrón genérico), pero **nunca** la solución de un
ejercicio. Las reglas no negociables (sección 2) siguen mandando: se entrega el **problema**; la
lógica que resuelve la consigna la escribe el lector. El código de ejemplo sirve para **entender** una
herramienta, jamás para resolver un enunciado del libro.
---
## 8. Lo que está prohibido
- Escribir la solución, total o parcial, del enunciado (incluida la lógica en pseudocódigo). - Escribir la solución, total o parcial, del enunciado (incluida la lógica en pseudocódigo).
- Convertir el ejercicio en un proyecto grande, con build system, múltiples archivos o dependencias externas. - Convertir el ejercicio en un proyecto grande, con build system, múltiples archivos o dependencias externas.
@@ -156,7 +212,7 @@ Un ejercicio puede combinar conceptos de niveles anteriores, pero **no debe exig
--- ---
## 8. Flujo para agregar contenido ## 9. Flujo para agregar contenido
Checklist al crear o editar un ejercicio: Checklist al crear o editar un ejercicio:
@@ -175,7 +231,7 @@ Checklist al crear o editar un ejercicio:
--- ---
## 9. Generación de PDF (`dist/`) ## 10. Generación de PDF (`dist/`)
Cada capítulo trabajado se publica como **PDF** en `dist/`, con el **mismo nombre** que su Cada capítulo trabajado se publica como **PDF** en `dist/`, con el **mismo nombre** que su
Markdown: `book/12-arenas.md` → `dist/12-arenas.pdf`. Markdown: `book/12-arenas.md` → `dist/12-arenas.pdf`.
File diff suppressed because it is too large Load Diff
@@ -1,9 +1,9 @@
# Capítulo 13 — Entrada y salida estándar (sin archivos) # Capítulo 14 — Entrada y salida estándar (sin archivos)
> Capítulo intermedio, pero **escrito para que se entienda de verdad**. Se apoya en variables (`02`), > Capítulo intermedio, pero **escrito para que se entienda de verdad**. Se apoya en variables (`02`),
> operadores (`03`), `if` y bucles (`04`), funciones (`05`) y arreglos y cadenas (`06`). > operadores (`03`), `if` y bucles (`04`), funciones (`05`) y arreglos y cadenas (`06`).
> >
> Es el **puente** hacia el capítulo de archivos (`14-archivos`). Todo lo que aprendas acá sobre > Es el **puente** hacia el capítulo de archivos (`15-archivos`). Todo lo que aprendas acá sobre
> `stdin`, búferes y `EOF` lo vas a reusar tal cual para leer archivos. La única diferencia será que, > `stdin`, búferes y `EOF` lo vas a reusar tal cual para leer archivos. La única diferencia será que,
> en vez de leer del teclado, vas a leer de un archivo. > en vez de leer del teclado, vas a leer de un archivo.
@@ -30,7 +30,7 @@ del capítulo.
| **7** | Robustez | Que tu programa no se rompa nunca. | | **7** | Robustez | Que tu programa no se rompa nunca. |
| **8** | Proyecto final | Construís tu propia consola de comandos. | | **8** | Proyecto final | Construís tu propia consola de comandos. |
Los **ejercicios** se numeran en orden: `13.1`, `13.2`, `13.3`, y así. Cada uno trae su **escenario de Los **ejercicios** se numeran en orden: `14.1`, `14.2`, `14.3`, y así. Cada uno trae su **escenario de
prueba** (qué entra y qué tiene que salir) para que puedas **comprobar** tu solución. prueba** (qué entra y qué tiene que salir) para que puedas **comprobar** tu solución.
> **Regla de oro del libro:** el capítulo explica y muestra **cómo funciona** cada cosa, pero **los > **Regla de oro del libro:** el capítulo explica y muestra **cómo funciona** cada cosa, pero **los
@@ -243,7 +243,7 @@ diferencia:
## Práctica de la Parte 1 ## Práctica de la Parte 1
### Ejercicio 13.1 — Separar la salida útil de los avisos ### Ejercicio 14.1 — Separar la salida útil de los avisos
**Conceptos** · `stdout`, `stderr`, `fprintf`, redirección de salidas **Conceptos** · `stdout`, `stderr`, `fprintf`, redirección de salidas
@@ -278,14 +278,14 @@ Aviso: 3 registros tenían fecha inválida.
- [ ] Al correr con `>` y `2>`, cada mensaje cae en su archivo y ninguno aparece en el otro. - [ ] Al correr con `>` y `2>`, cada mensaje cae en su archivo y ninguno aparece en el otro.
- [ ] Usa `fprintf` indicando el flujo (`stdout`/`stderr`) en cada escritura. - [ ] Usa `fprintf` indicando el flujo (`stdout`/`stderr`) en cada escritura.
### Ejercicio 13.2 — Detective de flujos ### Ejercicio 14.2 — Detective de flujos
**Conceptos** · `stdout`, `stderr`, redirección (`>`, `2>`, `2>&1`), tuberías **Conceptos** · `stdout`, `stderr`, redirección (`>`, `2>`, `2>&1`), tuberías
**Contexto** · Antes de creer que entendiste los flujos, hay que **verlos**. Vas a conectar el mismo **Contexto** · Antes de creer que entendiste los flujos, hay que **verlos**. Vas a conectar el mismo
programa de varias maneras y comparar qué termina dónde. programa de varias maneras y comparar qué termina dónde.
**Consigna** · Tomá el programa de 13.1 (o escribí uno mínimo que mande una línea a `stdout` y otra a **Consigna** · Tomá el programa de 14.1 (o escribí uno mínimo que mande una línea a `stdout` y otra a
`stderr`) y corrélo de estas formas, anotando para cada una **qué queda en pantalla** y **qué en cada `stderr`) y corrélo de estas formas, anotando para cada una **qué queda en pantalla** y **qué en cada
archivo**: archivo**:
@@ -462,7 +462,7 @@ int fgetc(FILE *stream); /* igual que getc, pero siempre es función */
## Práctica de la Parte 2 ## Práctica de la Parte 2
### Ejercicio 13.3 — Contador de caracteres seguro ### Ejercicio 14.3 — Contador de caracteres seguro
**Conceptos** · `getchar`, `int` vs `char`, `EOF`, bytes altos (`0xFF`) **Conceptos** · `getchar`, `int` vs `char`, `EOF`, bytes altos (`0xFF`)
@@ -496,7 +496,7 @@ Caracteres leídos: 3
- [ ] Termina limpio en `EOF`, sin bucle infinito. - [ ] Termina limpio en `EOF`, sin bucle infinito.
- [ ] El resultado coincide con el tamaño real de la entrada. - [ ] El resultado coincide con el tamaño real de la entrada.
### Ejercicio 13.4 — ¿Cuántos saltos de línea hay? ### Ejercicio 14.4 — ¿Cuántos saltos de línea hay?
**Conceptos** · `getchar`, comparación de bytes, `'\n'`, `EOF` **Conceptos** · `getchar`, comparación de bytes, `'\n'`, `EOF`
@@ -617,7 +617,7 @@ limpiar los residuos que deja `scanf`. Guardátelo.
## Práctica de la Parte 3 ## Práctica de la Parte 3
### Ejercicio 13.5 — Protección contra desbordamiento ### Ejercicio 14.5 — Protección contra desbordamiento
**Conceptos** · `fgets` con búfer fijo, truncamiento, detección de líneas largas, descarte del resto **Conceptos** · `fgets` con búfer fijo, truncamiento, detección de líneas largas, descarte del resto
@@ -650,7 +650,7 @@ Aviso: la línea era más larga que el búfer (20 bytes) y fue recortada.
- [ ] El resto de la línea se descarta; no contamina la lectura siguiente. - [ ] El resto de la línea se descarta; no contamina la lectura siguiente.
- [ ] No hay desbordamiento ni comportamiento indefinido. - [ ] No hay desbordamiento ni comportamiento indefinido.
### Ejercicio 13.6 — Contador de palabras ### Ejercicio 14.6 — Contador de palabras
**Conceptos** · `fgets`, recorrido de una cadena, espacios, bucles **Conceptos** · `fgets`, recorrido de una cadena, espacios, bucles
@@ -783,7 +783,7 @@ limpiar es el bucle de 4.5.
## Práctica de la Parte 4 ## Práctica de la Parte 4
### Ejercicio 13.7 — Corrección de búfer tras `scanf` ### Ejercicio 14.7 — Corrección de búfer tras `scanf`
**Conceptos** · `scanf`, `fgets`, `\n` pendiente, limpieza del búfer **Conceptos** · `scanf`, `fgets`, `\n` pendiente, limpieza del búfer
@@ -816,7 +816,7 @@ Nombre: Ana
- [ ] `fgets` obtiene el nombre, **no** una línea vacía. - [ ] `fgets` obtiene el nombre, **no** una línea vacía.
- [ ] Muestra número y nombre correctos. - [ ] Muestra número y nombre correctos.
### Ejercicio 13.8 — Cuestionario de datos mixtos ### Ejercicio 14.8 — Cuestionario de datos mixtos
**Conceptos** · `scanf`, `getchar`, `fgets`, saltear blancos, orden de lectura, residuos **Conceptos** · `scanf`, `getchar`, `fgets`, saltear blancos, orden de lectura, residuos
@@ -854,7 +854,7 @@ Nombre: Juan Gómez
- [ ] No quedan residuos: la lectura del nombre **no** está "corrida". - [ ] No quedan residuos: la lectura del nombre **no** está "corrida".
- [ ] Comprueba los valores de retorno. - [ ] Comprueba los valores de retorno.
### Ejercicio 13.9 — Menú de opciones de longitud fija ### Ejercicio 14.9 — Menú de opciones de longitud fija
**Conceptos** · `getchar`, consumir el resto de la línea, bucles, validación **Conceptos** · `getchar`, consumir el resto de la línea, bucles, validación
@@ -1022,7 +1022,7 @@ int main(void) {
## Práctica de la Parte 5 ## Práctica de la Parte 5
### Ejercicio 13.10 — Validador de edad numérica ### Ejercicio 14.10 — Validador de edad numérica
**Conceptos** · `scanf`, valor de retorno, fallo de conversión, descarte de entrada inválida **Conceptos** · `scanf`, valor de retorno, fallo de conversión, descarte de entrada inválida
@@ -1052,7 +1052,7 @@ Salida: Entrada inválida: se esperaba un número entero.
- [ ] Con un número válido, lo muestra correctamente. - [ ] Con un número válido, lo muestra correctamente.
- [ ] No deja la entrada "sucia" para una lectura posterior. - [ ] No deja la entrada "sucia" para una lectura posterior.
### Ejercicio 13.11 — Extracción de tokens con formato avanzado ### Ejercicio 14.11 — Extracción de tokens con formato avanzado
**Conceptos** · `scanf` con ancho máximo (`%19s`), supresión (`*`), valor de retorno **Conceptos** · `scanf` con ancho máximo (`%19s`), supresión (`*`), valor de retorno
@@ -1082,7 +1082,7 @@ Salida: valor = 42
- [ ] Extrae el número correctamente en ambos escenarios. - [ ] Extrae el número correctamente en ambos escenarios.
- [ ] Comprueba el retorno de `scanf` (`== 1`). - [ ] Comprueba el retorno de `scanf` (`== 1`).
### Ejercicio 13.12 — La calculadora de una línea ### Ejercicio 14.12 — La calculadora de una línea
**Conceptos** · `scanf` con formato mixto (`%d %c %d`), valor de retorno **Conceptos** · `scanf` con formato mixto (`%d %c %d`), valor de retorno
@@ -1175,13 +1175,13 @@ Reglas prácticas:
2. **Cuando examinés bytes crudos, usá `unsigned char`.** Comparar `0xC3` contra un `char` con signo 2. **Cuando examinés bytes crudos, usá `unsigned char`.** Comparar `0xC3` contra un `char` con signo
trae resultados confusos. trae resultados confusos.
3. **Un `char` no alcanza para todo símbolo.** Para eso existen `wchar_t` y `char32_t` (capítulo 3. **Un `char` no alcanza para todo símbolo.** Para eso existen `wchar_t` y `char32_t` (capítulo
`15-tipos-stddef`). `16-tipos-stddef`).
4. **No adivines la codificación.** Si los acentos salen "raros", casi siempre es que la codificación 4. **No adivines la codificación.** Si los acentos salen "raros", casi siempre es que la codificación
del texto no coincide con la que espera la terminal. del texto no coincide con la que espera la terminal.
## Práctica de la Parte 6 ## Práctica de la Parte 6
### Ejercicio 13.13 — Filtro de terminadores de línea ### Ejercicio 14.13 — Filtro de terminadores de línea
**Conceptos** · `getchar`, `EOF`, `'\n'`, `'\r'`, `'\0'`, distinción de símbolos **Conceptos** · `getchar`, `EOF`, `'\n'`, `'\r'`, `'\0'`, distinción de símbolos
@@ -1222,7 +1222,7 @@ d
- [ ] Detecta `'\0'` como byte real `0x00` (no lo confunde con `EOF`). - [ ] Detecta `'\0'` como byte real `0x00` (no lo confunde con `EOF`).
- [ ] Termina en el primer `EOF`, con la etiqueta `<EOF>` incluida. - [ ] Termina en el primer `EOF`, con la etiqueta `<EOF>` incluida.
### Ejercicio 13.14 — Radiografía de un acento ### Ejercicio 14.14 — Radiografía de un acento
**Conceptos** · `getchar`, bytes altos, UTF-8 multibyte, `unsigned char` **Conceptos** · `getchar`, bytes altos, UTF-8 multibyte, `unsigned char`
@@ -1359,7 +1359,7 @@ entrada es válida. `strtod` funciona igual, pero para `double`.
## Práctica de la Parte 7 ## Práctica de la Parte 7
### Ejercicio 13.15 — Bucle robusto ante cierre de terminal ### Ejercicio 14.15 — Bucle robusto ante cierre de terminal
**Conceptos** · `getchar`, `EOF`, corte de bucles, fin de entrada por teclado **Conceptos** · `getchar`, `EOF`, corte de bucles, fin de entrada por teclado
@@ -1394,7 +1394,7 @@ Fin de la entrada (EOF). Chau.
- [ ] Con la entrada del ejemplo, informa **11** caracteres y **2** líneas. - [ ] Con la entrada del ejemplo, informa **11** caracteres y **2** líneas.
- [ ] Muestra un mensaje de cierre y termina. - [ ] Muestra un mensaje de cierre y termina.
### Ejercicio 13.16 — Validador de número a prueba de balas ### Ejercicio 14.16 — Validador de número a prueba de balas
**Conceptos** · `fgets`, `strtol`, validación de rango, detección de basura **Conceptos** · `fgets`, `strtol`, validación de rango, detección de basura
@@ -1455,7 +1455,7 @@ leer líneas acotadas, interpretar el comando, validar números, manejar residuo
## Ejercicio final ## Ejercicio final
### Ejercicio 13.17 — (JEFE) Simulador de consola de comandos interactiva ### Ejercicio 14.17 — (JEFE) Simulador de consola de comandos interactiva
**Conceptos** · `fgets`, `sscanf`, `stdin`/`stdout`/`stderr`, limpieza de búfer, validación numérica, **Conceptos** · `fgets`, `sscanf`, `stdin`/`stdout`/`stderr`, limpieza de búfer, validación numérica,
`EOF`, corte de bucles, comandos con formato. `EOF`, corte de bucles, comandos con formato.
@@ -1550,7 +1550,7 @@ tubería con búfer**. Todo lo demás se deduce de ahí.
`EOF`. `EOF`.
- **Un carácter no siempre es un byte**: una `á` son dos bytes. - **Un carácter no siempre es un byte**: una `á` son dos bytes.
Y el puente hacia lo que viene: **para C, un archivo es un flujo más**. En `14-archivos` vas a reusar Y el puente hacia lo que viene: **para C, un archivo es un flujo más**. En `15-archivos` vas a reusar
**exactamente** estas ideas —`fgetc`, `fgets`, `fscanf`, `feof`, los búferes, `EOF`— solo que sobre un **exactamente** estas ideas —`fgetc`, `fgets`, `fscanf`, `feof`, los búferes, `EOF`— solo que sobre un
flujo abierto con `fopen` en lugar de sobre `stdin`. Si dominaste este capítulo, el de archivos es flujo abierto con `fopen` en lugar de sobre `stdin`. Si dominaste este capítulo, el de archivos es
casi el mismo capítulo con una apertura y un cierre. casi el mismo capítulo con una apertura y un cierre.
+65 -65
View File
@@ -1,12 +1,12 @@
# Capítulo 14 — Archivos # Capítulo 15 — Archivos
> Capítulo intermedio/avanzado. Se apoya en lo aprendido sobre arreglos (`06`), punteros (`07`), > Capítulo intermedio/avanzado. Se apoya en lo aprendido sobre arreglos (`06`), punteros (`07`),
> `struct` (`08`), memoria dinámica (`09-memoria-dinamica`), entrada/salida estándar > `struct` (`08`), memoria dinámica (`09-memoria-dinamica`), entrada/salida estándar
> (`13-entrada-salida-estandar`) y arenas (`12-arenas`). > (`14-entrada-salida-estandar`) y arenas (`12-arenas`).
> Se recomienda leerlo después de tener claros `malloc`, `free`, el uso de punteros, > 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). > el manejo de `stdin`/`stdout`/`stderr` y la idea de reservar memoria en bloques (arenas).
## 14.1 ¿Por qué leer y escribir archivos? ## 15.1 ¿Por qué leer y escribir archivos?
Hasta ahora, nuestros programas intercambiaban información únicamente a través de la consola 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 (entrada por teclado y salida por pantalla). Esto está bien para ejercicios cortos, pero
@@ -17,7 +17,7 @@ archivos compactados.
Un archivo nos permite guardar información en disco para usarla más tarde, compartirla entre 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**. programas o procesarla por lotes. El desafío es hacerlo de forma **clara, segura y correcta**.
### 14.1.1 Texto vs Binario ### 15.1.1 Texto vs Binario
En C, los archivos se dividen en dos grandes categorías: En C, los archivos se dividen en dos grandes categorías:
@@ -32,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) usamos modos distintos: `r`, `w`, `a` para texto y `rb`, `wb`, `ab` (más `+` cuando corresponde)
para binario. para binario.
### 14.1.2 Recursos: abrir y cerrar ### 15.1.2 Recursos: abrir y cerrar
Todo archivo abierto consume un recurso del sistema. Por eso, **siempre hay que cerrarlo** Todo archivo abierto consume un recurso del sistema. Por eso, **siempre hay que cerrarlo**
cuando terminamos de usarlo. El par básico es: cuando terminamos de usarlo. El par básico es:
@@ -47,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 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. distintas estrategias de gestión de memoria/buffers.
## 14.2 Lectura y escritura de archivos de texto ## 15.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. 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 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. en torno al tipo `FILE *`, que es el **manejador** (handle) del archivo abierto.
### 14.2.1 Modos de apertura ### 15.2.1 Modos de apertura
`fopen` recibe la ruta y un **modo** que decide qué se puede hacer con el archivo: `fopen` recibe la ruta y un **modo** que decide qué se puede hacer con el archivo:
@@ -79,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 > 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 > 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 (14.5) es un > mezclada con píxeles— se abren con `"b"`. Ojo: el `\n` de la cabecera PPM del ejemplo (15.5) es un
> **byte real del archivo** (`0x0A`), no una traducción del modo texto. > **byte real del archivo** (`0x0A`), no una traducción del modo texto.
### 14.2.2 Referencia: funciones de texto ### 15.2.2 Referencia: funciones de texto
#### `fopen` — abrir un archivo #### `fopen` — abrir un archivo
```c ```c
FILE *fopen(const char *path, const char *mode); FILE *fopen(const char *path, const char *mode);
``` ```
- **Recibe:** `path`, la ruta del archivo; `mode`, el modo de apertura (ver 14.2.1). - **Recibe:** `path`, la ruta del archivo; `mode`, el modo de apertura (ver 15.2.1).
- **Devuelve:** un `FILE *` (el manejador del archivo abierto) o `NULL` si no se pudo abrir. - **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. - **Ojo:** hay que verificar siempre `NULL` antes de usar el manejador.
@@ -191,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 > 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 > 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" > **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 14.5.2 antes de leer > ese separador con `fgetc()`. Es exactamente lo que hace el ejemplo de la sección 15.5.2 antes de leer
> los píxeles. > los píxeles.
#### `feof` — ¿se llegó al final? #### `feof` — ¿se llegó al final?
@@ -230,7 +230,7 @@ int tolower(int c);
> `printf`, `scanf`, `malloc`, `free` y `sizeof` ya se vieron en capítulos anteriores; acá nos > `printf`, `scanf`, `malloc`, `free` y `sizeof` ya se vieron en capítulos anteriores; acá nos
> concentramos en lo específico de archivos. > concentramos en lo específico de archivos.
### 14.2.3 Ejemplo: leer un archivo carácter por carácter ### 15.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 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 pueda distinguirse el valor `EOF` (fin de archivo, normalmente `-1`). Este es el patrón clásico
@@ -266,7 +266,7 @@ Observá tres detalles que se repiten en **todos** los programas con archivos:
2. El bucle corta cuando `fgetc()` devuelve `EOF`. 2. El bucle corta cuando `fgetc()` devuelve `EOF`.
3. Se cierran **los dos** archivos, en orden inverso al que se abrieron. 3. Se cierran **los dos** archivos, en orden inverso al que se abrieron.
### 14.2.4 Ejemplo: leer línea por línea con `fgets` ### 15.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` 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 caracteres, o hasta encontrar un `\n` (que **deja incluido** en el buffer), o hasta el fin del
@@ -298,7 +298,7 @@ int main(void) {
> buffer, `fgets()` la entrega **cortada** en varios pedazos. Para este capítulo, asumimos líneas > buffer, `fgets()` la entrega **cortada** en varios pedazos. Para este capítulo, asumimos líneas
> razonables. > razonables.
### 14.2.5 Ejemplo: escribir con formato (`fprintf`) ### 15.2.5 Ejemplo: escribir con formato (`fprintf`)
`fprintf()` es a un archivo lo que `printf()` es a la pantalla: acepta el mismo formato. `fprintf()` es a un archivo lo que `printf()` es a la pantalla: acepta el mismo formato.
@@ -325,15 +325,15 @@ int main(void) {
Con modo `"w"` el archivo se **trunca** (si ya existía, se borra su contenido). Para **agregar** 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"`. al final sin borrar lo anterior, se usa el modo `"a"`.
## 14.3 Ejercicios: archivos de texto ## 15.3 Ejercicios: archivos de texto
> **Regla fundamental:** ningún ejercicio incluye código de solución. Solo se describe el problema, > **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 > entrada/salida, conceptos y criterios de aceptación. Se permiten fragmentos de entrada/salida
> esperada como ejemplos. > esperada como ejemplos.
Estos ejercicios trabajan sobre lo visto en la sección 14.2: `fgetc`, `fgets`, `fprintf` y `feof`. Estos ejercicios trabajan sobre lo visto en la sección 15.2: `fgetc`, `fgets`, `fprintf` y `feof`.
### Ejercicio 14.1 — Contador de líneas y caracteres (texto, básico) ### Ejercicio 15.1 — Contador de líneas y caracteres (texto, básico)
**Conceptos** · `FILE*`, `fopen`, `fclose`, `fgetc`, `feof` **Conceptos** · `FILE*`, `fopen`, `fclose`, `fgetc`, `feof`
@@ -376,7 +376,7 @@ incrementar al encontrar `\n`). Siempre validar que el archivo se abrió correct
- [ ] Cierra el archivo con `fclose()` antes de terminar. - [ ] Cierra el archivo con `fclose()` antes de terminar.
- [ ] Muestra salida con formato claro. - [ ] Muestra salida con formato claro.
### Ejercicio 14.2 — Copia de archivo de texto (texto, básico) ### Ejercicio 15.2 — Copia de archivo de texto (texto, básico)
**Conceptos** · `FILE*`, `fopen`, `fclose`, `fgetc`, `fputc` **Conceptos** · `FILE*`, `fopen`, `fclose`, `fgetc`, `fputc`
@@ -414,7 +414,7 @@ y escribir con `fputc()`. Verificar aperturas y cierres. No modificar el conteni
- [ ] Reporta errores de forma clara. - [ ] Reporta errores de forma clara.
- [ ] Cierra ambos archivos. - [ ] Cierra ambos archivos.
### Ejercicio 14.3 — Leer líneas y guardar filtradas (texto, intermedio) ### Ejercicio 15.3 — Leer líneas y guardar filtradas (texto, intermedio)
**Conceptos** · `fgets`, buffers, cadenas, condicionales **Conceptos** · `fgets`, buffers, cadenas, condicionales
@@ -464,7 +464,7 @@ Abrir archivos en modo texto.
- [ ] Informa cantidad de líneas copiadas. - [ ] Informa cantidad de líneas copiadas.
- [ ] Maneja errores de apertura correctamente. - [ ] Maneja errores de apertura correctamente.
## 14.4 Lectura y escritura de archivos binarios ## 15.4 Lectura y escritura de archivos binarios
Cuando trabajamos con datos estructurados o con formatos como imágenes, necesitamos leer/escribir 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 **bytes exactos**, sin que el sistema modifique nada (ni convierta finales de línea). Para eso
@@ -473,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 > **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á > 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 > **ImHex Web** (<https://web.imhex.werwolv.net/>): un editor hexadecimal que corre entero en el
> navegador. Abrí ahí el BMP de la sección 14.8.6 o el PPM de la 14.5.1, ubicá los offsets y > navegador. Abrí ahí el BMP de la sección 15.8.6 o el PPM de la 15.5.1, ubicá los offsets y
> contrastá campo por campo lo que muestra la herramienta con lo que escribe tu programa. > contrastá campo por campo lo que muestra la herramienta con lo que escribe tu programa.
### 14.4.1 Referencia: funciones binarias ### 15.4.1 Referencia: funciones binarias
#### `fread` — leer un bloque #### `fread` — leer un bloque
```c ```c
@@ -531,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, la estructura byte a byte del archivo** y leerlo correctamente según su especificación,
sin asumir conversiones mágicas. sin asumir conversiones mágicas.
### 14.4.2 Ejemplo: averiguar el tamaño de un archivo ### 15.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 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 moverse al final con `fseek()`, preguntar la posición con `ftell()` y volver al principio con
@@ -561,7 +561,7 @@ int main(void) {
> `long` alcanza para archivos de tamaño normal. Para archivos gigantes existen `fseeko()` y > `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. > `ftello()` (con `off_t`), pero no hacen falta en este capítulo.
### 14.4.3 Ejemplo: leer el archivo completo a memoria ### 15.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 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: `fread()` y **siempre** liberar al terminar:
@@ -600,7 +600,7 @@ int main(void) {
> `fread()` devuelve **cuántos elementos** leyó realmente. Puede leer menos de lo pedido si el > `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. > archivo se acorta o si ocurre un error, así que conviene comparar con lo esperado.
### 14.4.4 Ejemplo: leer una cabecera fija a una `struct` ### 15.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 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: vez dentro de una `struct` que tenga **exactamente** el mismo diseño de bytes:
@@ -641,14 +641,14 @@ int main(void) {
> `struct` en memoria puede **no coincidir** con el del archivo. En esos casos conviene leer los > `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. > campos de a uno con `fread()` a variables sueltas, en lugar de a una `struct` entera.
## 14.5 Ejemplo guiado: otro formato binario — PPM (Netpbm) ## 15.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** 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 (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 **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". separa muy bien "leer la cabecera" de "leer los píxeles".
### 14.5.1 Descripción del formato PPM (variante P6) ### 15.5.1 Descripción del formato PPM (variante P6)
Un archivo `.ppm` binario (variante **P6**) tiene esta estructura: Un archivo `.ppm` binario (variante **P6**) tiene esta estructura:
@@ -676,7 +676,7 @@ Algunas diferencias con BMP que conviene notar:
| Orden de las filas | Arriba → abajo | Abajo → arriba | | Orden de las filas | Arriba → abajo | Abajo → arriba |
| Relleno por fila (padding) | No tiene | Múltiplo de 4 bytes | | Relleno por fila (padding) | No tiene | Múltiplo de 4 bytes |
### 14.5.2 Cómo leerlo ### 15.5.2 Cómo leerlo
El siguiente programa lee la cabecera con `fscanf()`/`fgetc()` (son texto) y luego los píxeles con 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 `fread()` (son binario). El truco clave está en el **paso 3**: después de `maxval` hay
@@ -703,7 +703,7 @@ int main(void) {
} }
/* 2. ancho, alto y valor máximo (son números en ASCII). /* 2. ancho, alto y valor máximo (son números en ASCII).
* Detalle de fscanf: ver la sección 14.2.2. */ * Detalle de fscanf: ver la sección 15.2.2. */
int width, height, maxval; int width, height, maxval;
if (fscanf(fp, "%d %d %d", &width, &height, &maxval) != 3) { if (fscanf(fp, "%d %d %d", &width, &height, &maxval) != 3) {
fprintf(stderr, "cabecera PPM inválida\n"); fprintf(stderr, "cabecera PPM inválida\n");
@@ -750,14 +750,14 @@ int main(void) {
> mismas que necesitarás para BMP: leer y validar la firma, extraer dimensiones, consumir el > 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 > 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 > es que BMP agrega **orden invertido de filas** y **relleno (padding) por fila**, que veremos en la
> sección 14.8. > sección 15.8.
## 14.6 Gestión de memoria: `malloc/free` vs Arenas ## 15.6 Gestión de memoria: `malloc/free` vs Arenas
Al leer archivos, especialmente archivos binarios de tamaño variable o con estructuras anidadas, 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: necesitamos almacenar lo leído en memoria. Tenemos dos enfoques principales:
### 14.6.1 Con `malloc` y `free` ### 15.6.1 Con `malloc` y `free`
- Reservamos exactamente lo que necesitamos (`malloc` del tamaño leído). - Reservamos exactamente lo que necesitamos (`malloc` del tamaño leído).
- Liberamos cada bloque cuando ya no lo usamos (`free`). - Liberamos cada bloque cuando ya no lo usamos (`free`).
@@ -765,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`. - **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. También complica liberar todo ante un error a mitad del proceso.
### 14.6.2 Con arenas (bump allocator) ### 15.6.2 Con arenas (bump allocator)
Recordando el concepto del Capítulo 12: reservamos **un bloque grande** una sola vez, 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 avanzamos un cursor para repartir memoria y **liberamos todo junto** (reiniciamos cursor o
@@ -783,7 +783,7 @@ Aplicado a lectura de archivos:
a **leer archivos correctamente** y que puedas implementar la lectura **usando malloc/free** a **leer archivos correctamente** y que puedas implementar la lectura **usando malloc/free**
y también **usando arenas**, entendiendo cuándo conviene cada uno. y también **usando arenas**, entendiendo cuándo conviene cada uno.
## 14.7 Errores y robustez ## 15.7 Errores y robustez
Al trabajar con archivos, hay que considerar fallas posibles: Al trabajar con archivos, hay que considerar fallas posibles:
@@ -801,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 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. o estructurando el código para asegurar el cierre.
## 14.8 El formato BMP: documentación de referencia ## 15.8 El formato BMP: documentación de referencia
Antes del desafío final, necesitamos entender el formato que vamos a interpretar: **BMP** 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: (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. guarda los píxeles **sin compresión** y documenta su estructura con cabeceras bien definidas.
### 14.8.1 Estructura general de un BMP ### 15.8.1 Estructura general de un BMP
Un archivo `.bmp` se compone de estas partes, en este orden: Un archivo `.bmp` se compone de estas partes, en este orden:
@@ -816,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. 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. 4. **Datos de píxeles** (pixel data): la matriz de píxeles.
### 14.8.2 BITMAPFILEHEADER (14 bytes) ### 15.8.2 BITMAPFILEHEADER (14 bytes)
| Offset | Tamaño | Campo | Descripción | | Offset | Tamaño | Campo | Descripción |
|---|---|---|---| |---|---|---|---|
@@ -826,7 +826,7 @@ Un archivo `.bmp` se compone de estas partes, en este orden:
| 8 | 2 | `bfReserved2` | Reservado, debe ser 0. | | 8 | 2 | `bfReserved2` | Reservado, debe ser 0. |
| 10 | 4 | `bfOffBits` | Offset en bytes donde comienzan los datos de píxeles. | | 10 | 4 | `bfOffBits` | Offset en bytes donde comienzan los datos de píxeles. |
### 14.8.3 BITMAPINFOHEADER (40 bytes, versión más común) ### 15.8.3 BITMAPINFOHEADER (40 bytes, versión más común)
| Offset | Tamaño | Campo | Descripción | | Offset | Tamaño | Campo | Descripción |
|---|---|---|---| |---|---|---|---|
@@ -845,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 **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. necesitamos para saber cómo leer los píxeles.
### 14.8.4 Datos de píxeles ### 15.8.4 Datos de píxeles
Los píxeles comienzan en el offset indicado por `bfOffBits` (campo del archivo, offset 10). Los píxeles comienzan en el offset indicado por `bfOffBits` (campo del archivo, offset 10).
@@ -868,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. Las filas reales se leen desde el final hacia el principio si la imagen es bottom-up.
### 14.8.5 Paleta (solo para 1, 4 u 8 bpp) ### 15.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 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). (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`). La paleta comienza inmediatamente después de la cabecera de bits (offset `14 + biSize`).
### 14.8.6 Anatomía de un BMP real: ejemplo byte a byte ### 15.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 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 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 14.8. mismo archivo que usamos más adelante para verificar el Ejercicio 15.8.
<img width="150" alt="Render de ejemplo-bmp-5x3.bmp: grilla de 5×3 píxeles con los bordes dibujados en negro" <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;" style="image-rendering: pixelated;"
@@ -958,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 > 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. > rapidísima de saber si tu programa leyó bien las cabeceras y el padding.
### 14.8.7 Cómo leer un BMP (flujo sugerido) ### 15.8.7 Cómo leer un BMP (flujo sugerido)
1. Abrir el archivo en binario (`rb`). 1. Abrir el archivo en binario (`rb`).
2. Leer los 14 bytes del **BITMAPFILEHEADER**. 2. Leer los 14 bytes del **BITMAPFILEHEADER**.
@@ -974,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 > el byte menos significativo va primero. Leerlos con `fread` en un `uint32_t` funciona bien en
> máquinas little-endian (x86/x64). > máquinas little-endian (x86/x64).
## 14.9 Mostrar la imagen en pantalla (opcional): SDL2 ## 15.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 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 **mostrar la imagen** en una ventana. C no trae esto en su biblioteca estándar: dibujar ventanas es
@@ -984,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). > 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. > SDL2 es una **dependencia externa**; si tu entorno no la tiene, podés saltearla sin problema.
### 14.9.1 La idea ### 15.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 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: buffer de píxeles** en una superficie dibujable, sin copiar los datos:
@@ -1013,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 **intercambian** entre rojo y azul. Este es el error más común: colores correctos pero con rojo y
azul cambiados. azul cambiados.
### 14.9.2 Programa mínimo de visualización ### 15.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 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 `R, G, B`, con la fila `0` **arriba**). Muestra la ventana hasta que la cierres o presiones una
@@ -1060,14 +1060,14 @@ int main(void) {
} }
``` ```
### 14.9.3 El detalle de las filas: BMP es bottom-up ### 15.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 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**. 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`) La solución es copiar cada fila a su posición espejada (`fila destino = height - 1 - fila origen`)
al momento de cargar el buffer. al momento de cargar el buffer.
### 14.9.4 Compilar y enlazar ### 15.9.4 Compilar y enlazar
SDL2 se enlaza como cualquier biblioteca externa. Con `gcc` y la utilidad `sdl2-config`: SDL2 se enlaza como cualquier biblioteca externa. Con `gcc` y la utilidad `sdl2-config`:
@@ -1083,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 > explícito del capítulo. Esta sección es la excepción deliberada y por eso queda marcada como
> opcional. > opcional.
## 14.10 Ejercicios: archivos binarios ## 15.10 Ejercicios: archivos binarios
Estos ejercicios ponen a prueba la segunda mitad del capítulo: archivos binarios con `fread` y Estos ejercicios ponen a prueba la segunda mitad del capítulo: archivos binarios con `fread` y
`fwrite` (sección 14.4), el formato PPM (14.5), arenas (14.6), errores (14.7) y el formato BMP `fwrite` (sección 15.4), el formato PPM (15.5), arenas (15.6), errores (15.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 (15.8). La regla fundamental de la sección 15.3 sigue en pie: **ningún ejercicio incluye código
de solución**. de solución**.
### Ejercicio 14.4 — Lectura binaria con `fread` (binario, intermedio) ### Ejercicio 15.4 — Lectura binaria con `fread` (binario, intermedio)
**Conceptos** · Archivos binarios, `fopen` con `rb`, `fread`, buffers de bytes **Conceptos** · Archivos binarios, `fopen` con `rb`, `fread`, buffers de bytes
@@ -1127,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). - [ ] Muestra primeros N bytes en formato legible (hex).
- [ ] Libera memoria con `free()` y cierra archivo. - [ ] Libera memoria con `free()` y cierra archivo.
### Ejercicio 14.5 — Lectura binaria usando arena (arenas + binario, intermedio) ### Ejercicio 15.5 — Lectura binaria usando arena (arenas + binario, intermedio)
**Conceptos** · Arenas (bump allocator), lectura binaria, bloques grandes **Conceptos** · Arenas (bump allocator), lectura binaria, bloques grandes
**Consigna** · Repetir el Ejercicio 14.4, pero **reservando toda la memoria necesaria desde una arena** **Consigna** · Repetir el Ejercicio 15.4, pero **reservando toda la memoria necesaria desde una arena**
en lugar de llamar `malloc` directamente para el buffer completo. El programa debe: 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 - 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). (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). - 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 14.4). - Mostrar tamaño y primeros N bytes (igual salida que 15.4).
- Liberar **todo junto** al final (reiniciar cursor o liberar el bloque de arena completo). **No** - Liberar **todo junto** al final (reiniciar cursor o liberar el bloque de arena completo). **No**
hacer `free` por byte/elemento. hacer `free` por byte/elemento.
**Entrada** · Ruta del archivo binario y `N`. **Entrada** · Ruta del archivo binario y `N`.
**Salida** · Igual que Ejercicio 14.4. **Salida** · Igual que Ejercicio 15.4.
**Identificadores sugeridos** · `arena`, `arenaBlock`, `capacity`, `offset` **Identificadores sugeridos** · `arena`, `arenaBlock`, `capacity`, `offset`
@@ -1158,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. - [ ] Libera memoria con **un único `free`** (bloque de arena). No hay frees por partes.
- [ ] No hay fugas de memoria ni double-free. - [ ] No hay fugas de memoria ni double-free.
### Ejercicio 14.6 — Escritura binaria estructurada (binario, avanzado) ### Ejercicio 15.6 — Escritura binaria estructurada (binario, avanzado)
**Conceptos** · `fwrite`, estructuras, archivos binarios, persistencia **Conceptos** · `fwrite`, estructuras, archivos binarios, persistencia
@@ -1196,23 +1196,23 @@ Verificar cantidad leída.
- [ ] Maneja memoria con `malloc/free` adecuadamente. - [ ] Maneja memoria con `malloc/free` adecuadamente.
- [ ] No corrompe datos al escribir/leer. - [ ] No corrompe datos al escribir/leer.
### Ejercicio 14.7 — Persistencia binaria con arena (binario + arenas, avanzado) ### Ejercicio 15.7 — Persistencia binaria con arena (binario + arenas, avanzado)
**Conceptos** · Arenas, `fwrite`/`fread`, buffers desde arena **Conceptos** · Arenas, `fwrite`/`fread`, buffers desde arena
**Consigna** · Modificar el Ejercicio 14.6 para que **el buffer de lectura** (donde se cargan **Consigna** · Modificar el Ejercicio 15.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 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 puede reservarse el arreglo original desde arena si se desea. El objetivo es practicar
lectura binaria usando espacio de arena. lectura binaria usando espacio de arena.
**Entrada/Salida** · Igual que Ejercicio 14.6. **Entrada/Salida** · Igual que Ejercicio 15.6.
**Criterios de aceptación** **Criterios de aceptación**
- [ ] Buffer de lectura reservado desde arena. - [ ] Buffer de lectura reservado desde arena.
- [ ] Lectura con `fread` correcta. - [ ] Lectura con `fread` correcta.
- [ ] Verificación OK. - [ ] Verificación OK.
- [ ] Liberación con único `free` del bloque de arena (sin frees individuales). - [ ] Liberación con único `free` del bloque de arena (sin frees individuales).
### Ejercicio 14.8 — (JEFE) Leer un archivo BMP pixel a pixel ### Ejercicio 15.8 — (JEFE) Leer un archivo BMP pixel a pixel
**Conceptos** · Cabeceras binarias (`fread` de estructuras), little-endian, `fseek`, `ftell`, **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. interpretación de píxeles, `malloc/free` y/o arenas (opcional), validación de formato.
@@ -1262,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 - 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). frecuentes o un arreglo de conteos).
- Opción extra: repetir la lectura usando una **arena** para los buffers de píxeles. - 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 14.8.6 (102 bytes, tres filas de - **Archivo de prueba ideal**: el BMP de 5×3 de la sección 15.8.6 (102 bytes, tres filas de
color sólido). Es tan chico que verificás todo a mano: `bfOffBits = 54`, `rowSize = 16` (15 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 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`. `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 14.8. Si querés mostrar la imagen, mirá la - La documentación del formato está en la sección 15.8. Si querés mostrar la imagen, mirá la
sección 14.9 (SDL2, opcional). sección 15.9 (SDL2, opcional).
**Criterios de aceptación** **Criterios de aceptación**
- [ ] Valida la firma `BM` antes de continuar. - [ ] Valida la firma `BM` antes de continuar.
@@ -1279,4 +1279,4 @@ Salida: Archivo: imagen.bmp
- [ ] Maneja archivos inexistentes o corruptos con mensajes de error claros. - [ ] Maneja archivos inexistentes o corruptos con mensajes de error claros.
- [ ] Libera memoria correctamente (con `free` o un solo `free` de la arena). - [ ] 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) 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 14.9). - [ ] (Extra) Muestra la imagen en una ventana con SDL2 (ver sección 15.9).
@@ -1,4 +1,4 @@
# Capítulo 15 — Tipos más usados de C # Capítulo 16 — Tipos más usados de C
> Capítulo avanzado. Se apoya en tipos primitivos (`02`), operadores (`03`), arreglos (`06`), > Capítulo avanzado. Se apoya en tipos primitivos (`02`), operadores (`03`), arreglos (`06`),
> punteros (`07`) y `struct` (`08`). > punteros (`07`) y `struct` (`08`).
@@ -9,7 +9,7 @@
--- ---
## 15.1 ¿Por qué no alcanza con un `int`? ## 16.1 ¿Por qué no alcanza con un `int`?
Un `int` resuelve muchísimos casos, pero **no responde de forma portable** tres preguntas: Un `int` resuelve muchísimos casos, pero **no responde de forma portable** tres preguntas:
@@ -53,7 +53,7 @@ datos** (valores en bits):
--- ---
## 15.2 El mapa de los tipos ## 16.2 El mapa de los tipos
Casi ningún tipo "con nombre" es palabra del lenguaje: son **typedefs** de una cabecera. Estos son 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): 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):
--- ---
## 15.3 `size_t` — los tamaños ## 16.3 `size_t` — los tamaños
**Cabecera:** `<stddef.h>` **Cabecera:** `<stddef.h>`
@@ -101,7 +101,7 @@ uses en un `for` inverso (`for (size_t i = n - 1; i >= 0; i--)` es **infinito**)
--- ---
## 15.4 `wchar_t` — caracteres anchos ## 16.4 `wchar_t` — caracteres anchos
**Cabecera:** `<stddef.h>` **Cabecera:** `<stddef.h>`
@@ -135,7 +135,7 @@ clave no es "agrandar" el tipo, sino **elegir el correcto**. **Se imprimen con `
--- ---
## 15.5 `NULL` — el puntero nulo ## 16.5 `NULL` — el puntero nulo
**Cabecera:** `<stddef.h>` **Cabecera:** `<stddef.h>`
@@ -148,7 +148,7 @@ conceptual.
--- ---
## 15.6 `bool` — verdadero o falso ## 16.6 `bool` — verdadero o falso
**Cabecera:** `<stdbool.h>` (C99; en C23, palabra clave) **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
--- ---
## 15.7 Enteros de ancho exacto ## 16.7 Enteros de ancho exacto
**Cabecera:** `<stdint.h>` **Cabecera:** `<stdint.h>`
@@ -205,7 +205,7 @@ printf("%llu\n", (unsigned long long)big);
--- ---
## 15.8 ¿Tengo que dejar de usar `int`? ## 16.8 ¿Tengo que dejar de usar `int`?
**No.** Estos tipos **no reemplazan** a `int`: lo **complementan** para casos puntuales. El `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. 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`. - **`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 > **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 15.7): si lo usás para contar, se desborda enseguida. Y encima la > hasta 127 (ver la tabla de 16.7): si lo usás para contar, se desborda enseguida. Y encima la
> aritmética se hace en `int` igual. > aritmética se hace en `int` igual.
```c ```c
@@ -255,7 +255,7 @@ int c = a + b; /* 200: la suma se calcula en int, y al achicar se desborda */
--- ---
## 15.9 ¿Los tipos chicos ahorran memoria? ## 16.9 ¿Los tipos chicos ahorran memoria?
**Depende de dónde.** Guardar **muchos** valores en tipos chicos sí ahorra memoria; una variable **Depende de dónde.** Guardar **muchos** valores en tipos chicos sí ahorra memoria; una variable
suelta, no. suelta, no.
@@ -290,7 +290,7 @@ struct Color2 { int r, g, b; }; /* 12 bytes */
--- ---
## 15.10 Errores comunes ## 16.10 Errores comunes
- Comparar un `int` negativo con `sizeof` o `strlen` (el `-1` se vuelve `SIZE_MAX`). - 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`. - 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 */
--- ---
## 15.11 Ejercicios ## 16.11 Ejercicios
> De **noob** a **pro**, con dificultad creciente. Cada ejercicio declara sus conceptos objetivo; > 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, > 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) > nunca el algoritmo) para que compares lo que imprimís. Compilá con un estándar moderno (C11 o C23)
> y avisos activos (`-Wall -Wextra`). > y avisos activos (`-Wall -Wextra`).
### Ejercicio 15.1 — Radiografía de tipos ### Ejercicio 16.1 — Radiografía de tipos
**Conceptos** · `sizeof`, `size_t`, `printf` (`%zu`), tipos de `<stddef.h>` y `<stdint.h>` **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 15.2 — Sumar con `size_t` ### Ejercicio 16.2 — Sumar con `size_t`
**Conceptos** · `size_t`, arreglos, `for`, casos borde **Conceptos** · `size_t`, arreglos, `for`, casos borde
@@ -369,7 +369,7 @@ count = 1 ; [-5] -> -5
--- ---
### Ejercicio 15.3 — El índice que se convierte en gigante ### Ejercicio 16.3 — El índice que se convierte en gigante
**Conceptos** · conversiones con/sin signo, `size_t`, comparaciones **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 15.4 — Texto que no entra en un byte ### Ejercicio 16.4 — Texto que no entra en un byte
**Conceptos** · `wchar_t`, `L""`, `%lc`, `%ls`, `<uchar.h>` **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 15.5 — El entero de ancho exacto (pro) ### Ejercicio 16.5 — El entero de ancho exacto (pro)
**Conceptos** · `<stdint.h>`, tipos de ancho exacto, portabilidad **Conceptos** · `<stdint.h>`, tipos de ancho exacto, portabilidad
@@ -457,7 +457,7 @@ total = 123456789012345ULL (uint64_t) -> 123456789012345
--- ---
## 15.12 Cierre ## 16.12 Cierre
Los tipos de C no son un adorno: son la forma de decir **qué querés representar** y **de qué 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, tamaño**. `size_t` para tamaños, `uintN_t`/`intN_t` para ancho exacto, `bool` para verdades,
Binary file not shown.
Binary file not shown.
Binary file not shown.