Update arena chapter in the programming exercises book:

- Adjust page numbers in the PDF to reflect content changes.
- Correct exercise references and improve explanations for arena concepts.
- Enhance code examples for clarity and consistency.
- Add detailed descriptions for memory alignment and checkpoint functionalities.
- Include additional exercises focusing on heterogeneous records and performance comparisons.
This commit is contained in:
2026-10-13 10:42:03 -03:00
parent 5786e9cde0
commit c749ba4116
4 changed files with 174 additions and 32 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
{ {
"fingerprint": "d3c21ce024c6ffe6e44e8dd85565ff6f6df97bc4" "fingerprint": "60c5eae54c7e739d5e839304b313804bc547b807"
} }
+2
View File
@@ -6,6 +6,7 @@ Last updated: 2026-10-13
## Sources scanned ## Sources scanned
- .opencode\skills
- C:\Users\horacio\.agents\skills - C:\Users\horacio\.agents\skills
- C:\Users\horacio\.config\opencode\skills - C:\Users\horacio\.config\opencode\skills
- C:\Users\horacio\.claude\skills - C:\Users\horacio\.claude\skills
@@ -23,6 +24,7 @@ Last updated: 2026-10-13
| Skill | Trigger / description | Scope | Path | | Skill | Trigger / description | Scope | Path |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| `book-pdf` | Generar o regenerar los PDF de los capítulos del libro de C en dist/, con diseño consistente (resaltado de sintaxis, fuente mono para código, notas con fondo de color). Trigger - pdf, generar pdf, exportar capítulo, dist, md-to-pdf, print.css, "convertir a pdf", "rehacer pdf". | project | `C:\Users\horacio\Desarrollo\c-programming\.opencode\skills\book-pdf\SKILL.md` |
| `branch-pr` | Create Gentle AI pull requests with issue-first checks. Trigger: creating, opening, or preparing PRs for review. | user | `C:\Users\horacio\.config\opencode\skills\branch-pr\SKILL.md` | | `branch-pr` | Create Gentle AI pull requests with issue-first checks. Trigger: creating, opening, or preparing PRs for review. | user | `C:\Users\horacio\.config\opencode\skills\branch-pr\SKILL.md` |
| `chained-pr` | Trigger: PRs over 400 lines, stacked PRs, review slices. Split oversized changes into chained PRs that protect review focus. | user | `C:\Users\horacio\.config\opencode\skills\chained-pr\SKILL.md` | | `chained-pr` | Trigger: PRs over 400 lines, stacked PRs, review slices. Split oversized changes into chained PRs that protect review focus. | user | `C:\Users\horacio\.config\opencode\skills\chained-pr\SKILL.md` |
| `cognitive-doc-design` | Design docs that reduce cognitive load. Trigger: writing guides, READMEs, RFCs, onboarding, architecture, or review-facing docs. | user | `C:\Users\horacio\.config\opencode\skills\cognitive-doc-design\SKILL.md` | | `cognitive-doc-design` | Design docs that reduce cognitive load. Trigger: writing guides, READMEs, RFCs, onboarding, architecture, or review-facing docs. | user | `C:\Users\horacio\.config\opencode\skills\cognitive-doc-design\SKILL.md` |
+171 -31
View File
@@ -84,7 +84,7 @@ Cuando tenés **muchos objetos pequeños con la misma vida útil** y los liberá
## 12.3 Un primer ejemplo mínimo (comentado) ## 12.3 Un primer ejemplo mínimo (comentado)
> Este es **material didáctico para entender el concepto**. Los ejercicios del 12.7 te van a pedir > Este es **material didáctico para entender el concepto**. Los ejercicios del 12.8 te van a pedir
> que lo **extiendas** con features que acá no están. No es la solución de ningún ejercicio. > que lo **extiendas** con features que acá no están. No es la solución de ningún ejercicio.
La estructura central tiene solo **tres campos**: La estructura central tiene solo **tres campos**:
@@ -104,6 +104,14 @@ typedef struct {
- `capacity` es el tamaño total. Sirve para saber cuándo **no hay más lugar**. - `capacity` es el tamaño total. Sirve para saber cuándo **no hay más lugar**.
- `offset` es el cursor. Empieza en 0. Solo avanza. - `offset` es el cursor. Empieza en 0. Solo avanza.
> **¿Una arena guarda un solo tipo o varios?** Una arena **no tiene tipo**: guarda *bytes*. El tipo
> no vive en la arena, sino en **cómo vos interpretás** el puntero que te devolvió `arena_alloc`.
> Por eso una **misma** arena puede contener, al mismo tiempo, tipos distintos —`int`, `double`,
> structs, cadenas—, cada uno en su propio hueco, siempre que respetes la **alineación** (ver 12.4.1).
> El ejemplo de la `main` en 12.3 ya lo hace: pide un `Point` y, del **mismo** bloque, un arreglo de
> 100 `int`. Lo único que la arena **no** hace es acordarse por vos a qué tipo corresponde cada
> puntero: eso queda de tu lado.
### Crear y destruir la arena ### Crear y destruir la arena
```c ```c
@@ -157,6 +165,12 @@ renglón donde está el cursor" y `a->offset += size;` es "bajo al renglón sigu
Mirá que **nunca hay un `free` por objeto**. No existe `arena_free(ptr)` porque no hace falta: Mirá que **nunca hay un `free` por objeto**. No existe `arena_free(ptr)` porque no hace falta:
cuando el llamador termine, llama a `arena_reset` o a `arena_destroy`. cuando el llamador termine, llama a `arena_reset` o a `arena_destroy`.
> **Reservar es solo el primer paso.** El puntero que devuelve `arena_alloc` es una dirección
> común y corriente: guardás y recuperás datos por él (`*p = ...`, `x = *p`), igual que con
> cualquier otro puntero. La arena no es una caja fuerte ni un tipo especial: es memoria normal
> que se libera en bloque. Por eso, en los ejercicios no alcanza con pedir bytes — hay que
> **escribir** en ese espacio y **leerlo de vuelta** para comprobar que sirve.
### Reiniciar sin liberar: reaprovechar el bloque ### Reiniciar sin liberar: reaprovechar el bloque
```c ```c
@@ -295,7 +309,39 @@ pedir ambas variantes.
--- ---
## 12.7 Ejercicios ## 12.7 Dato de color: arenas en programas que probablemente uses
No es una curiosidad académica: este truco está metido en software masivo que usás todos los días.
Cada caso nombra **qué parte** del programa la usa y **para qué**, como simple información (no hace
falta entenderlos a fondo):
- **Google Chrome, Microsoft Edge, Node.js** (los tres corren el motor V8): V8 reserva los nodos del
*parser* y del compilador de JavaScript en "zonas". La documentación lo dice tal cual: los bloques
"no se pueden liberar por separado... se liberan todos juntos en una sola operación", y las zonas
se usan "en todo el parser y los compiladores de V8". Terminado el script, la zona entera se tira
de una sola vez.
- **Mozilla Firefox** (motor SpiderMonkey): usa un asignador llamado `LifoAlloc`, que su propia doc
define como un *bump allocator*: "asignación rápida, pero incapaz de liberar asignaciones
individuales". Se usa mientras se parsea y se compila (JIT) el JavaScript, y trae `mark`/`release`
— el mismo *checkpoint* / *restore* del ejercicio 12.8.
- **Juegos hechos con Unity** (miles, y gran parte del mercado móvil): Unity documenta
`Allocator.Temp` como un *stack allocator* del que "cada frame, el hilo principal crea un
allocator Temp y lo libera por completo al final del frame". Es exactamente el `arena_reset` por
frame del ejercicio 12.2, pero corriendo 60 veces por segundo.
- **Python** (CPython): el asignador de objetos chicos usa bloques llamados, literalmente, "arenas"
(de 256 KiB). El archivo se llama, sin vueltas, `Objects/obmalloc.c`.
- **Java y Android** (y todo lo que corre encima, de apps móviles a Minecraft): la máquina virtual
asigna objetos nuevos casi "empujando" un puntero en la generación joven (el famoso TLAB), sin
buscar huecos. El aseo de la basura, otra vez, se hace en bloque.
De los que mencionaste —Word, Excel, Photoshop, Notepad, Paint— no tengo una fuente que afirme
"acá usan una arena" y no te lo voy a inventar. Pero el concepto es el mismo: la próxima vez que
leas "pool", "zone", "arena" o "region allocator" en el código de un programa grande, ya sabés de
qué hablan.
---
## 12.8 Ejercicios
> Dificultad incremental, de **noob** a **pro**. Cada ejercicio declara sus conceptos objetivo. > Dificultad incremental, de **noob** a **pro**. Cada ejercicio declara sus conceptos objetivo.
> Resolvelos **usando esos conceptos**. Sin código de solución: el libro te da el problema, no la respuesta. > Resolvelos **usando esos conceptos**. Sin código de solución: el libro te da el problema, no la respuesta.
@@ -314,17 +360,18 @@ una arena. Simplificación: ignoramos alineación por ahora.
**Consigna** · Implementá una estructura `Arena` y las funciones `arena_create`, **Consigna** · Implementá una estructura `Arena` y las funciones `arena_create`,
`arena_alloc` y `arena_destroy`. `arena_alloc` reparte el cursor y devuelve `NULL` si no hay `arena_alloc` y `arena_destroy`. `arena_alloc` reparte el cursor y devuelve `NULL` si no hay
lugar. lugar. Después de reservar, **guardá un valor por el puntero** (por ejemplo, un `int`) y **leelo de
vuelta**: el espacio sirve solo si podés escribir y recuperar datos en él.
**Entrada** · Una capacidad en bytes y pedidos de tamaño variable. **Entrada** · Una capacidad en bytes y pedidos de tamaño variable.
**Salida** · Punteros válidos dentro del bloque, o `NULL` cuando la arena se llena. **Salida** · Punteros válidos dentro del bloque, o `NULL` cuando la arena se llena; y el valor guardado se recupera igual.
**Escenario de prueba** · **Escenario de prueba** ·
``` ```
capacity = 16 capacity = 16
1. arena_create(16) -> arena con 16 bytes disponibles 1. arena_create(16) -> arena con 16 bytes disponibles
2. arena_alloc(4) -> OK (base + 0) 2. int *p = arena_alloc(4) -> OK (base + 0) ; *p = 7 ; leer *p -> 7
3. arena_alloc(4) -> OK (base + 4) 3. arena_alloc(4) -> OK (base + 4)
4. arena_alloc(8) -> OK (base + 8) -> la arena queda llena 4. arena_alloc(8) -> OK (base + 8) -> la arena queda llena
5. arena_alloc(1) -> NULL ("no hay espacio") 5. arena_alloc(1) -> NULL ("no hay espacio")
@@ -336,6 +383,7 @@ capacity = 16
**Criterios de aceptación** · **Criterios de aceptación** ·
- `arena_alloc` devuelve direcciones **contiguas** y crecientes. - `arena_alloc` devuelve direcciones **contiguas** y crecientes.
- Se guarda un valor por el puntero y se recupera intacto (el espacio es **usable**, no solo reservado).
- No se escribe **nunca** fuera del bloque. - No se escribe **nunca** fuera del bloque.
- Un único `free` en `arena_destroy` libera todo. - Un único `free` en `arena_destroy` libera todo.
- `arena_alloc` devuelve `NULL` exactamente cuando no hay lugar. - `arena_alloc` devuelve `NULL` exactamente cuando no hay lugar.
@@ -351,8 +399,8 @@ liberar 60 veces por segundo es un desperdicio. Simplificación: no hay gráfico
reservas. reservas.
**Consigna** · Agregá `arena_reset` que vuelva el cursor a 0 sin liberar el bloque. Simulá N **Consigna** · Agregá `arena_reset` que vuelva el cursor a 0 sin liberar el bloque. Simulá N
"frames": en cada uno reservá varios objetos, usalos, y reseteá la arena. La dirección **base** del "frames": en cada uno reservá varios objetos, **escribí valores en ellos y leelos de vuelta**, y
bloque no debe cambiar entre frames. recién después reseteá la arena. La dirección **base** del bloque no debe cambiar entre frames.
**Entrada** · Cantidad de frames y cuántos bytes reserva cada frame. **Entrada** · Cantidad de frames y cuántos bytes reserva cada frame.
**Salida** · Para cada frame, la dirección del primer objeto reservado (debe repetirse) y el uso total. **Salida** · Para cada frame, la dirección del primer objeto reservado (debe repetirse) y el uso total.
@@ -362,15 +410,14 @@ bloque no debe cambiar entre frames.
capacity = 16 ; frames = 3 ; cada frame reserva 4 + 4 + 4 = 12 capacity = 16 ; frames = 3 ; cada frame reserva 4 + 4 + 4 = 12
frame 0: frame 0:
alloc(4) -> base + 0 int *a = alloc(4); *a = 10; leer *a -> 10 (offset 0)
alloc(4) -> base + 4 int *b = alloc(4); *b = 20; leer *b -> 20 (offset 4)
alloc(4) -> base + 8 reset -> offset vuelve a 0
reset -> offset vuelve a 0
frame 1: frame 1:
alloc(4) -> base + 0 (misma dirección que en el frame 0) int *a = alloc(4) -> base + 0 (misma dirección que en el frame 0)
... *a = 30; leer *a -> 30 (el valor viejo ya no está: hueco reutilizado)
frame 2: frame 2:
alloc(4) -> base + 0 (otra vez la misma dirección) int *a = alloc(4) -> base + 0 (otra vez la misma dirección)
``` ```
Esperado: las tres primeras direcciones son idénticas y el programa hace **un solo `malloc`** en total. Esperado: las tres primeras direcciones son idénticas y el programa hace **un solo `malloc`** en total.
@@ -382,6 +429,7 @@ Pensá qué pasa si guardás un puntero de un frame y lo usás en el siguiente.
**Criterios de aceptación** · **Criterios de aceptación** ·
- El bloque se reserva **una sola vez**. - El bloque se reserva **una sola vez**.
- La primera dirección de cada frame es idéntica. - La primera dirección de cada frame es idéntica.
- Cada frame guarda y recupera sus valores correctamente del espacio reutilizado.
- No hay ningún `malloc` dentro del bucle de frames. - No hay ningún `malloc` dentro del bucle de frames.
--- ---
@@ -406,6 +454,7 @@ múltiplo de 8. Agregá una función `arena_is_aligned` que diga si una direcci
capacity = 32 ; alineación = 8 capacity = 32 ; alineación = 8
1. arena_alloc(3) -> base + 0 (offset 0 -> 8) 1. arena_alloc(3) -> base + 0 (offset 0 -> 8)
escribir 'A' en base + 0 y leer -> 'A'
2. arena_alloc(1) -> base + 8 (offset 8 -> 16) 2. arena_alloc(1) -> base + 8 (offset 8 -> 16)
3. arena_alloc(5) -> base + 16 (offset 16 -> 24) 3. arena_alloc(5) -> base + 16 (offset 16 -> 24)
4. arena_alloc(9) -> NULL (9 se redondea a 16 y solo quedan 8 bytes) 4. arena_alloc(9) -> NULL (9 se redondea a 16 y solo quedan 8 bytes)
@@ -422,6 +471,7 @@ Además: `arena_is_aligned(base + 0)`, `+ 8`, `+ 16`, `+ 24` -> todos `true` (m
**Criterios de aceptación** · **Criterios de aceptación** ·
- Toda dirección devuelta es múltiplo de 8. - Toda dirección devuelta es múltiplo de 8.
- Reservar 1 byte consume 8 de capacidad. - Reservar 1 byte consume 8 de capacidad.
- Se escribe y se lee un valor desde un hueco alineado.
- No se pierde memoria fuera de lo necesario (no redondeás de más). - No se pierde memoria fuera de lo necesario (no redondeás de más).
--- ---
@@ -464,7 +514,48 @@ vez. Si usás `void *` + cast, explicá por qué el cast es seguro.
--- ---
### Ejercicio 12.5 — Arena para cadenas: `arena_strdup` ### Ejercicio 12.5 — Una arena, muchos tipos
**Conceptos** · `void *`, `cast`, `sizeof`, alineación, punteros
**Contexto** · Un equipo de telemetría junta lecturas de sensores de distinto tipo —temperatura
(`double`), cantidad de eventos (`int`), estado (`char`)— y, por velocidad, las guarda **juntas** en
un único bloque temporal en lugar de reservar cada una por separado. Simplificación: no hay
sensores reales, solo los valores mezclados.
**Consigna** · Usando **una sola** arena, reservá y guardá tres valores de **tipos distintos** (un
`double`, un `int`, un `char`). Escribí cada valor, leelos de vuelta y comprobá que coinciden.
Verificá además que cada puntero quede alineado a su tipo.
**Entrada** · Tres valores de tipos distintos.
**Salida** · Los tres valores leídos correctamente desde la **misma** arena, y la comprobación de alineación.
**Escenario de prueba** ·
```
capacity = 64 ; alineación = 8
1. double *t = arena_alloc(&a, sizeof(double)); -> base + 0 (offset 0 -> 8)
2. int *c = arena_alloc(&a, sizeof(int)); -> base + 8 (offset 8 -> 16)
3. char *s = arena_alloc(&a, sizeof(char)); -> base + 16 (offset 16 -> 24)
4. *t = 36.5; *c = 42; *s = 'A';
leer de vuelta -> 36.5, 42, 'A'
```
Los tres punteros apuntan a huecos distintos del **mismo** bloque, y cada uno es múltiplo de 8.
**Identificadores sugeridos** · `temperature`, `eventCount`, `status`, `arena_alloc`
**Restricciones / pistas** · Un `arena_alloc` por valor, todos de la misma arena. No los envuelvas
en un struct: la gracia es ver tipos sueltos conviviendo. Cuidá el `cast` al tipo correcto al leer.
**Criterios de aceptación** ·
- Los tres valores viven en **una sola** arena.
- Se leen de vuelta con el tipo correcto y coinciden con lo escrito.
- Cada puntero queda alineado a 8 (y por lo tanto a su tipo).
- Un único `arena_destroy` libera todo.
---
### Ejercicio 12.6 — Arena para cadenas: `arena_strdup`
**Conceptos** · cadenas, `strlen`, `memcpy`, punteros, terminador `'\0'` **Conceptos** · cadenas, `strlen`, `memcpy`, punteros, terminador `'\0'`
@@ -501,7 +592,7 @@ capacity = 16
--- ---
### Ejercicio 12.6 — Estadísticas de uso ### Ejercicio 12.7 — Estadísticas de uso
**Conceptos** · `struct`, punteros, aritmética, operadores relacionales **Conceptos** · `struct`, punteros, aritmética, operadores relacionales
@@ -541,7 +632,7 @@ Distinguí "usado ahora" de "usado alguna vez".
--- ---
### Ejercicio 12.7 — Checkpoints (arenas temporales) ### Ejercicio 12.8 — Checkpoints (arenas temporales)
**Conceptos** · punteros, copia de estado, `size_t`, anidamiento lógico **Conceptos** · punteros, copia de estado, `size_t`, anidamiento lógico
@@ -561,14 +652,15 @@ reservado después). Usalos para procesar secciones temporales anidadas.
capacity = 32 capacity = 32
1. cp0 = arena_checkpoint(&a) -> 0 1. cp0 = arena_checkpoint(&a) -> 0
2. arena_alloc(8) -> base + 0 (offset 8) 2. int *x = arena_alloc(8); *x = 100; leer *x -> 100 (base + 0, offset 8)
3. arena_alloc(8) -> base + 8 (offset 16) 3. arena_alloc(8) -> base + 8 (offset 16)
4. cp1 = arena_checkpoint(&a) -> 16 4. cp1 = arena_checkpoint(&a) -> 16
5. arena_alloc(8) -> base + 16 (offset 24) 5. int *tmp = arena_alloc(8); *tmp = 999 (base + 16, offset 24)
6. arena_restore(&a, cp1) -> offset 16 (se descartan los 8 del paso 5) 6. arena_restore(&a, cp1) -> offset 16 (se descarta `tmp`)
7. arena_alloc(16) -> base + 16 (offset 32) -> reutiliza el hueco 7. leer *x -> 100 (sobrevive al restore); usar `tmp` ahora es inválido
8. arena_restore(&a, cp0) -> offset 0 (se descarta todo) 8. arena_alloc(16) -> base + 16 (offset 32) -> reutiliza el hueco
9. arena_alloc(32) -> base + 0 (offset 32) -> ahora sí entra 9. arena_restore(&a, cp0) -> offset 0 (se descarta todo)
10. arena_alloc(32) -> base + 0 (offset 32) -> ahora sí entra
``` ```
Ojo: el puntero devuelto en el paso 5 queda inválido después del paso 6. Ojo: el puntero devuelto en el paso 5 queda inválido después del paso 6.
@@ -579,12 +671,13 @@ punteros reservados después del checkpoint quedan inválidos al restaurar.
**Criterios de aceptación** · **Criterios de aceptación** ·
- Restaurar a un checkpoint rehabilita exactamente la capacidad liberada. - Restaurar a un checkpoint rehabilita exactamente la capacidad liberada.
- Lo reservado **antes** del checkpoint conserva su valor tras restaurar.
- Checkpoints anidados funcionan (restaurar al más interno, luego al externo). - Checkpoints anidados funcionan (restaurar al más interno, luego al externo).
- Restaurar es O(1): solo escribe el offset. - Restaurar es O(1): solo escribe el offset.
--- ---
### Ejercicio 12.8 — Arena que crece (cadena de regiones) ### Ejercicio 12.9 — Arena que crece (cadena de regiones)
**Conceptos** · `malloc`, `free`, structs enlazados, manejo de errores **Conceptos** · `malloc`, `free`, structs enlazados, manejo de errores
@@ -622,7 +715,7 @@ debe liberar **todas** las regiones, no solo la actual. Pensá el manejo de erro
--- ---
### Ejercicio 12.9 — Arena como almacén de una colección ### Ejercicio 12.10 — Arena como almacén de una colección
**Conceptos** · structs, arreglos dinámicos, punteros, `arena_alloc` **Conceptos** · structs, arreglos dinámicos, punteros, `arena_alloc`
@@ -657,7 +750,7 @@ salida esperada:
**Identificadores sugeridos** · `Contact`, `ContactList`, `contacts`, `load_contacts` **Identificadores sugeridos** · `Contact`, `ContactList`, `contacts`, `load_contacts`
**Restricciones / pistas** · Los nombres también van en la arena (`arena_strdup`). Si el arreglo de **Restricciones / pistas** · Los nombres también van en la arena (`arena_strdup`). Si el arreglo de
contactos puede crecer, decidí entre pedir capacidad fija o usar la arena que crece (12.8). contactos puede crecer, decidí entre pedir capacidad fija o usar la arena que crece (12.9).
**Criterios de aceptación** · **Criterios de aceptación** ·
- **Cero** `malloc`/`free` por contacto: toda la memoria sale de la arena. - **Cero** `malloc`/`free` por contacto: toda la memoria sale de la arena.
@@ -666,7 +759,7 @@ contactos puede crecer, decidí entre pedir capacidad fija o usar la arena que c
--- ---
### Ejercicio 12.10 — Arena sin `malloc` (buffer estático) ### Ejercicio 12.11 — Arena sin `malloc` (buffer estático)
**Conceptos** · arreglos locales, duración de almacenamiento, punteros, límites **Conceptos** · arreglos locales, duración de almacenamiento, punteros, límites
@@ -686,7 +779,7 @@ la crea, y demostralo con un caso que **debe fallar** (explicado en comentarios,
unsigned char buffer[4096]; (variable local) ; alineación = 8 unsigned char buffer[4096]; (variable local) ; alineación = 8
1. arena_init_on(&a, buffer, 4096) -> arena sobre memoria prestada 1. arena_init_on(&a, buffer, 4096) -> arena sobre memoria prestada
2. arena_alloc(1000) -> OK, dentro de [buffer, buffer + 4096) 2. char *s = arena_alloc(1000); copiar "hola arena" y leer -> "hola arena"
3. arena_alloc(3000) -> OK (offset 4000) 3. arena_alloc(3000) -> OK (offset 4000)
4. arena_alloc(96) -> OK (llenó los 4096) 4. arena_alloc(96) -> OK (llenó los 4096)
5. arena_alloc(1) -> NULL 5. arena_alloc(1) -> NULL
@@ -705,11 +798,12 @@ hacer `free`. Refactorizá para que la arena funcione tanto con memoria propia c
**Criterios de aceptación** · **Criterios de aceptación** ·
- No se usa `malloc` en ningún lado. - No se usa `malloc` en ningún lado.
- `arena_destroy` distingue "memoria propia" de "memoria prestada" y no libera la prestada. - `arena_destroy` distingue "memoria propia" de "memoria prestada" y no libera la prestada.
- Se guarda y se lee una cadena desde el buffer prestado.
- Se explica y se evidencia el peligro de devolver punteros fuera de alcance. - Se explica y se evidencia el peligro de devolver punteros fuera de alcance.
--- ---
### Ejercicio 12.11 — Arena para un árbol sintáctico (pro) ### Ejercicio 12.12 — Arena para un árbol sintáctico (pro)
**Conceptos** · structs con punteros, recursión, arena, cadenas, `enum` **Conceptos** · structs con punteros, recursión, arena, cadenas, `enum`
@@ -749,7 +843,7 @@ vida útil: todos los nodos viven hasta terminar el análisis.
--- ---
### Ejercicio 12.12 — Arena vs `malloc`: medí y decidí (pro) ### Ejercicio 12.13 — Arena vs `malloc`: medí y decidí (pro)
**Conceptos** · arena, `malloc`/`free`, medición de tiempo (`clock`), análisis de complejidad **Conceptos** · arena, `malloc`/`free`, medición de tiempo (`clock`), análisis de complejidad
@@ -793,7 +887,53 @@ observable). El contraejemplo es obligatorio: medir no es lo mismo que entender.
--- ---
## 12.8 Cierre ### Ejercicio 12.14 — Registros heterogéneos con unión etiquetada (pro)
**Conceptos** · `enum`, `union`, punteros, arena, arreglo dinámico, `switch`
**Contexto** · Un sistema de auditoría registra eventos de distinto tipo —inicio de sesión (con
usuario), compra (con monto) y error (con código)— en un mismo flujo temporal. Cada evento tiene
una **forma distinta**, pero todos deben vivir juntos y liberarse de una sola vez. Simplificación:
los eventos se generan a mano, sin persistencia.
**Consigna** · Definí un tipo `Event` con un `enum kind` y una `union` de cargas útiles (usuario
como cadena, monto como `double`, código como `int`). Creá varios eventos de **distinto tipo** en
una **misma** arena (las cadenas también salen de la arena), recorrelos y procesalos según su
etiqueta (`switch`), e imprimí un resumen. Liberá todo con un solo `arena_destroy`.
**Entrada** · Una lista de eventos de tipos variados.
**Salida** · Cada evento procesado según su tipo, un total de eventos y un conteo por tipo.
**Ejemplo** ·
```
entrada:
LOGIN usuario = "ana"
PURCHASE monto = 19.99
ERROR código = 404
salida esperada:
LOGIN ana
PURCHASE 19.99
ERROR 404
total eventos = 3
login = 1, purchase = 1, error = 1
```
**Identificadores sugeridos** · `Event`, `EventKind`, `USER_MAX`, `make_login`, `make_purchase`, `make_error`, `process_events`
**Restricciones / pistas** · La `union` ahorra memoria: todos los payloads comparten el mismo
espacio y el `enum` te dice cuál es válido en cada momento. Reservá el evento **y** su cadena en la
arena. Nunca leas el campo de la `union` que no corresponde al `kind`. Sin `malloc` por evento.
**Criterios de aceptación** ·
- Un solo `arena_destroy` libera los eventos y sus cadenas.
- El procesamiento respeta la etiqueta (`switch` sobre `kind`), sin leer campos inválidos.
- El conteo por tipo y el total de eventos son exactos.
- No hay `malloc`/`free` por evento.
---
## 12.9 Cierre
Una arena no es magia: es **disciplina sobre la duración de los datos**. Si entendés que un Una arena no es magia: es **disciplina sobre la duración de los datos**. Si entendés que un
conjunto de objetos **nace, vive y muere junto**, ganás velocidad y simplicidad enormes. Si te conjunto de objetos **nace, vive y muere junto**, ganás velocidad y simplicidad enormes. Si te
BIN
View File
Binary file not shown.