Compare commits
16 Commits
cfaa0ca470
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 04be717bc7 | |||
| c693541103 | |||
| 950a48b544 | |||
| 54ac3d140e | |||
| e2195a7ed2 | |||
| 913efb475b | |||
| 361de2745c | |||
| 82008f51bf | |||
| f4f56db493 | |||
| 392cf493d1 | |||
| 00441678a4 | |||
| 0177bbbceb | |||
| 64e8d471b5 | |||
| 187dd293e3 | |||
| 9be881e043 | |||
| e4a362a8fb |
@@ -262,3 +262,121 @@ Reglas de diseño (resumen):
|
||||
|
||||
> Si se modifica `assets/pdf/print.css`, hay que **regenerar todos** los capítulos para que ningún
|
||||
> PDF quede con un diseño distinto.
|
||||
|
||||
---
|
||||
|
||||
## Protocolo de escritura de archivos extensos
|
||||
|
||||
Cuando el agente (humano o IA) necesita escribir un archivo Markdown de contenido grande
|
||||
(≥ 600 líneas, como los capítulos del libro), **no usar una única llamada a `write` con todo el contenido**.
|
||||
Los herramientas de escritura pasan el contenido dentro de un string JSON y los caracteres especiales
|
||||
(tres backticks ```, `$`, `{`, `}`, `\`, comillas) pueden romper el parseo.
|
||||
|
||||
### Enfoque correcto (confirmado en producción)
|
||||
|
||||
1. **Escribir con `write` solo los primeros ~500-600 líneas**, hasta la primera sección completa
|
||||
(hasta un `---` o final de una parte). El archivo se crea correctamente porque el contenido
|
||||
es manejable para el parser JSON.
|
||||
|
||||
2. **Usar `edit` para ir agregando las secciones restantes**. Cada llamada a `edit` reemplaza
|
||||
una cadena corta (`oldString`) por otra más larga (`newString`). La cadena a buscar es siempre
|
||||
muy breve (ej: el último texto del archivo actual) y la cadena de reemplazo incluye la nueva sección.
|
||||
|
||||
```
|
||||
oldString: "- [ ] Termina limpiamente al escribir \"exit\"." ← solo la última línea existente
|
||||
newString: "- [ ] Termina limpiamente al escribir \"exit\".\n\n---\n# PARTE 5 — ..." ← misma + nueva sección
|
||||
```
|
||||
|
||||
3. **Verificar el conteo de líneas** con un bash/PowerShell simple después de cada edit grande,
|
||||
para confirmar que la sección se incorporó correctamente:
|
||||
```
|
||||
Get-Content book\22-file-descriptors.md | Measure-Object -Line
|
||||
```
|
||||
|
||||
### Por qué fallaba el enfoque anterior
|
||||
|
||||
Un archivo de capítulo tiene ~1200-1500 líneas con:
|
||||
- Bloques de código C con backticks triples (```` ```c ````) que el parser JSON confunde
|
||||
- Strings con comillas escapadas (`\"`) que colisionan con las del string JSON
|
||||
- Caracteres especiales como `$` en ejemplos de shell o `\n` en strings C
|
||||
|
||||
Con chunks de ≤ 600 líneas, el contenido cabe en un string JSON sin romper el parseo.
|
||||
|
||||
### Regla práctica
|
||||
|
||||
> **Nunca escribir más de 600 líneas de una sola vez con `write`.** Si el contenido total es mayor,
|
||||
> usar `write` para la primera parte y `edit` sucesivo para el resto.
|
||||
|
||||
---
|
||||
|
||||
## 11. Corrección de caracteres malformados (mojibake)
|
||||
|
||||
Los capítulos en español pueden acumular **codificación doble**: bytes UTF-8 almacenados como si
|
||||
fuera Latin-1/CP1252, lo que genera mojibake visible como `ú`, `Práctica` o caracteres
|
||||
`\xef\xbf\xbd` (replacement char) en vez de "práctica". Esto pasa cuando el parser JSON del tool
|
||||
de escritura corrompe los bytes multibyte.
|
||||
|
||||
### Cómo detectar
|
||||
|
||||
```python
|
||||
import os
|
||||
path = r"C:\Users\horacio\Desarrollo\c-programming\book\TU-CAPITULO.md"
|
||||
with open(path, "rb") as f:
|
||||
raw = f.read()
|
||||
|
||||
# Si hay bytes no ASCII pero el archivo se decodifica como UTF-8 bien formado,
|
||||
# puede haber entidades HTML o caracteres dobles codificados.
|
||||
|
||||
try:
|
||||
text = raw.decode("utf-8")
|
||||
except UnicodeDecodeError:
|
||||
print("NO es UTF-8 — hay corrupción de encoding")
|
||||
|
||||
# Buscar replacement char U+FFFD (EF BF BD)
|
||||
if b"\xef\xbf\xbd" in raw:
|
||||
print("Encontrado replacement char — el archivo tiene mojibake")
|
||||
|
||||
# Buscar entidades HTML sueltas (ú, é, ñ)
|
||||
for ent in [b"ú", b"é", b"ñ", b"á", b"ó", b"ú"]:
|
||||
if ent in raw:
|
||||
print(f"Entidad HTML detectada: {ent}")
|
||||
```
|
||||
|
||||
### Cómo corregir (reconstruir UTF-8 limpio)
|
||||
|
||||
Si el archivo está corrupto, **borrar y reconstruir** desde un script Python que escriba en
|
||||
UTF-8 nativo. El pattern probado en producción es:
|
||||
|
||||
1. **Borrar el archivo corrupto.** No intentes repararlo con `edit` — si ya tiene entidades HTML
|
||||
mezcladas con bytes dobles, la reparación parcial deja residuos.
|
||||
|
||||
2. **Escribir con un script Python que use `encoding='utf-8'`.** El script construye el contenido
|
||||
como strings de Python (que son Unicode internos) y lo escribe como bytes UTF-8 limpios.
|
||||
No uses `write` del agente para contenido > 600 líneas.
|
||||
|
||||
```python
|
||||
# rebuild_chapter.py
|
||||
chapter_file = r"C:\Users\horacio\Desarrollo\c-programming\book\25-drm-kms.md"
|
||||
|
||||
with open(chapter_file, "w", encoding="utf-8") as f:
|
||||
f.write("# Capítulo 25 — DRM/KMS\n") # texto en Unicode → se escribe como UTF-8 limpio
|
||||
```
|
||||
|
||||
3. **Si el contenido es largo**, dividí en chunks de ~250-300 líneas y uso `open(..., 'a')` para
|
||||
append cada chunk al archivo ya creado.
|
||||
|
||||
4. **Verificar** que no queden caracteres corruptos:
|
||||
```python
|
||||
raw = open(path, "rb").read()
|
||||
text = raw.decode("utf-8", errors="replace")
|
||||
assert "\ufffd" not in text # sin replacement chars
|
||||
for ent in [b"ú", b"é", b"ñ"]:
|
||||
assert ent not in raw # sin entidades HTML sueltas
|
||||
```
|
||||
|
||||
### Regla de prevención
|
||||
|
||||
> **Nunca pasar texto con acentos/ñ directamente en un string JSON `write`.** Si el contenido del
|
||||
> capítulo tiene caracteres UTF-8 multibyte, escribirlo como un bloque grande en `write` puede
|
||||
> corromper la codificación. La forma segura es: script Python que construya el Unicode interno y
|
||||
> lo escriba con `encoding="utf-8"`.
|
||||
|
||||
+288
-13
@@ -231,33 +231,308 @@ que lo vuelven "de producción".
|
||||
|
||||
### 12.4.1 Alineación de memoria
|
||||
|
||||
Los procesadores no leen cualquier dirección igual de rápido, y algunos **exigen** que ciertos tipos
|
||||
empiecen en direcciones múltiplo de su tamaño (`int` a múltiplo de 4, `double` a múltiplo de 8, etc.).
|
||||
Si repartís tamaños impares (por ejemplo 3 bytes), la próxima asignación puede quedar **desalineada**
|
||||
y provocar comportamientos raros o lentitud.
|
||||
#### Por qué a la CPU le importa dónde empieza un dato
|
||||
|
||||
La solución es **redondear el tamaño hacia arriba** hasta un múltiplo de la alineación:
|
||||
Los procesadores no leen cualquier dirección igual de rápido, y algunos **exigen** que ciertos tipos
|
||||
empiecen en direcciones "redondas". Si repartís tamaños impares (3 bytes, 5, 1...) el próximo dato
|
||||
puede quedar **desalineado** y provocar lentitud o, en arquitecturas estrictas, un *crash*
|
||||
(comportamiento indefinido).
|
||||
|
||||
Pero antes de seguir hay que desarmar una trampa de vocabulario, porque es la raíz de tu duda:
|
||||
|
||||
> **"Múltiplo de su tamaño" es un atajo que solo vale para los primitivos.** La regla de verdad es:
|
||||
> cada tipo exige que su dirección sea **múltiplo de su ALINEACIÓN**, y la alineación **no siempre
|
||||
> coincide con el tamaño**. Para `int`, `double` y `char` da igual; para un `struct`, casi nunca.
|
||||
> Eso es exactamente lo que hace que te preguntes si podés mezclar tipos. Podés. Seguí leyendo.
|
||||
|
||||
#### La alineación es una propiedad del TIPO, no del dato ni de la arena
|
||||
|
||||
Una arena **no tiene tipo**: guarda bytes y no sabe qué vas a poner adentro. La alineación no es una
|
||||
propiedad del valor ni de la arena: es una propiedad **del tipo** que vos vas a escribir en ese
|
||||
hueco. El lenguaje ya sabe, para cada tipo, cuánto exige:
|
||||
|
||||
| Tipo | Tamaño | Alineación típica (x86-64) |
|
||||
|------|:------:|:--------------------------:|
|
||||
| `char` | 1 | 1 |
|
||||
| `short` | 2 | 2 |
|
||||
| `int` | 4 | 4 |
|
||||
| `long`, `double`, puntero | 8 | 8 |
|
||||
| `struct` | según sus miembros (con relleno) | **= la mayor alineación de sus miembros** |
|
||||
|
||||
#### La idea que te salva: UNA alineación para todos
|
||||
|
||||
Acá está la respuesta a tu primera pregunta. ¿Podés tener `int`, `char`, `double` y structs complejos
|
||||
en la **misma** arena, bien alineados? **Sí, y no hace falta calcular nada por tipo.**
|
||||
|
||||
La clave: si **cada** bloque arranca en un múltiplo de 8, entonces arranca también en un múltiplo de
|
||||
4, de 2 y de 1. Un múltiplo de 8 *es* múltiplo de todos los divisores de 8. Así que alineando
|
||||
**todo** a 8 cubrís a la vez a `char` (1), `int` (4), `double`/puntero (8) y a cualquier struct cuya
|
||||
alineación sea ≤ 8:
|
||||
|
||||
```text
|
||||
base+0 base+8 base+16 base+24
|
||||
| | | |
|
||||
v v v v
|
||||
[ double ][ int ][ char ][ struct ... ]
|
||||
^8 ^8 ^8 ^8
|
||||
todos múltiplos de 8 -> 8, 4, 2 y 1 quedan satisfechos
|
||||
```
|
||||
|
||||
Por eso el ejemplo de `main` en 12.3 puede pedir un `Point` y después 100 `int` del mismo bloque: no
|
||||
calculás la posición de nadie, **alineás cada reparto al mismo valor** y listo.
|
||||
|
||||
> **¿Qué alineación universal uso?** `8` alcanza para `int`, `double` y punteros. Para estar
|
||||
> cubierto ante *cualquier* tipo (incluido algún SIMD o `long double`), usá
|
||||
> `ARENA_ALIGN = _Alignof(max_align_t)` (normalmente 16). Es el valor que el estándar considera
|
||||
> suficiente para todo. Un poquito más de desperdicio, cero dolores de cabeza.
|
||||
|
||||
#### Structs: por qué el tamaño NO te dice la alineación
|
||||
|
||||
Esta es la parte que confunde. Mirá:
|
||||
|
||||
```c
|
||||
#define ARENA_ALIGN 8 // alineamos a 8 bytes
|
||||
struct Mixed { char tag; int value; }; // sizeof = 8 | _Alignof = 4
|
||||
struct Pair { double a; double b; }; // sizeof = 16 | _Alignof = 8
|
||||
struct Quad { int a, b, c, d; }; // sizeof = 16 | _Alignof = 4
|
||||
```
|
||||
|
||||
¿Por qué `Mixed` mide 8 y no 5? Porque el compilador **inserta 3 bytes de relleno** (*padding*)
|
||||
después de `tag`, para que el `int` caiga alineado a 4. Y mide 8 (múltiplo de 4) para que, en un
|
||||
arreglo `Mixed items[10]`, el `value` del segundo elemento también quede alineado.
|
||||
|
||||
De ahí sale el dato que te ahorra todo el cálculo:
|
||||
|
||||
> **La alineación de un tipo SIEMPRE divide a su tamaño.** Es una garantía del estándar de C, y
|
||||
> existe precisamente para que los arreglos funcionen. Consecuencia directa: si alineás el bloque a
|
||||
> la alineación del struct, **todos** sus miembros caen alineados solos. Nunca tenés que ubicar
|
||||
> `tag` ni `value` a mano.
|
||||
|
||||
Entonces, tu pregunta "¿cómo calculo, en base al `sizeof`, la posición que debe ocupar un struct
|
||||
complejo?" tiene una respuesta incómoda y liberadora: **no lo calcules desde el `sizeof`.** El
|
||||
`sizeof` te dice *cuánto ocupa*, no *dónde tiene que empezar*. Para saber eso, pedile la alineación
|
||||
al lenguaje:
|
||||
|
||||
- `_Alignof(Type)` (C11) te da la alineación en bytes.
|
||||
- `alignof(Type)` con `<stdalign.h>` (el alias con nombre lindo).
|
||||
- `_Alignas(16)` en una variable te fuerza *su* alineación.
|
||||
|
||||
> **Cuidado con el `sizeof` como fuente de alineación.** `struct Pair` (size 16) pide 8, no 16;
|
||||
> `struct Quad` (size 16) pide 4, no 16. Si asumís "alineo a `sizeof`" vas a desperdiciar y, peor,
|
||||
> a equivocarte con structs de tamaño impar (p. ej. size 24 con align 8). La alineación y el tamaño
|
||||
> son primos hermanos, no gemelos.
|
||||
|
||||
#### Ejemplo paso a paso: alineación y tamaño de un struct
|
||||
|
||||
Vamos con un caso completo, miembro por miembro:
|
||||
|
||||
```c
|
||||
struct Record {
|
||||
int a; // 4 bytes
|
||||
int b; // 4 bytes
|
||||
double c; // 8 bytes
|
||||
char d; // 1 byte
|
||||
};
|
||||
```
|
||||
|
||||
**Paso 1 — la alineación de cada miembro.** En x86/x64, lo habitual es:
|
||||
|
||||
| Miembro | Tipo | `_Alignof` |
|
||||
|:-------:|:----:|:----------:|
|
||||
| `a` | `int` | 4 |
|
||||
| `b` | `int` | 4 |
|
||||
| `c` | `double` | 8 |
|
||||
| `d` | `char` | 1 |
|
||||
|
||||
**Paso 2 — la alineación del struct.** Es la **regla del mayor**: el alineamiento de una estructura
|
||||
es el mayor alineamiento de entre todos sus miembros.
|
||||
|
||||
```text
|
||||
max(4, 4, 8, 1) = 8
|
||||
```
|
||||
|
||||
Por lo tanto `_Alignof(struct Record)` es **8**.
|
||||
|
||||
**Paso 3 — acomodar los miembros (y el relleno).** El compilador ubica cada miembro en el primer
|
||||
offset que sea múltiplo de *su* alineación:
|
||||
|
||||
| Miembro | Alineación | Offset donde cae | Ocupa |
|
||||
|:-------:|:----------:|:----------------:|:-----:|
|
||||
| `a` | 4 | 0 | 0..3 |
|
||||
| `b` | 4 | 4 | 4..7 |
|
||||
| `c` | 8 | 8 | 8..15 |
|
||||
| `d` | 1 | 16 | 16 |
|
||||
| *relleno final* | — | 17 | 17..23 (7 bytes) |
|
||||
|
||||
Byte a byte queda así:
|
||||
|
||||
```text
|
||||
offset 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |17 ... 23
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+----------+
|
||||
| a (int) | b (int) | c (double) | d | relleno |
|
||||
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+----------+
|
||||
align ^4 ^4 ^8 ^1
|
||||
```
|
||||
|
||||
- `b` termina en 8 y `c` pide 8: **entra directo, sin relleno interno**.
|
||||
- `d` ocupa 1 byte (offset 16), pero el struct completo tiene que medir un múltiplo de 8.
|
||||
|
||||
**Paso 4 — el `sizeof`.** Contenido real: `4 + 4 + 8 + 1 = 17`. Para que sea múltiplo de 8, se agregan
|
||||
**7 bytes de relleno al final**:
|
||||
|
||||
```text
|
||||
sizeof(struct Record) = 17 + 7 = 24
|
||||
```
|
||||
|
||||
> **La trampa del relleno final.** El `sizeof` **no** es la suma de los miembros: incluye el relleno.
|
||||
> Acá `4 + 4 + 8 + 1 = 17`, pero `sizeof` es **24**, no 16. Esos 7 bytes "fantasma" existen para que,
|
||||
> en un arreglo `struct Record items[7]`, cada elemento arranque alineado a 8. Si te olvidás del
|
||||
> relleno final, el número no cierra.
|
||||
|
||||
#### `_Alignof`: ¿operador, macro o función?
|
||||
|
||||
`_Alignof` **no es una función** (no se llama en runtime, no existe un símbolo con ese nombre) y
|
||||
**tampoco es, en sí mismo, una macro**. Es un **operador unario**, igual que `sizeof`:
|
||||
|
||||
- Lleva el guión bajo (`_Alignof`) porque en C11 entró como **palabra clave reservada**: los
|
||||
identificadores con `_` + mayúscula están reservados al lenguaje, así no choca con código viejo.
|
||||
- Se evalúa en **tiempo de compilación** y produce un valor de tipo `size_t` (la cantidad de bytes de
|
||||
alineación).
|
||||
- Su operando es un **tipo** entre paréntesis (`_Alignof(double)`, `_Alignof(struct Record)`), **no**
|
||||
una variable.
|
||||
- El `_` inicial es feo a propósito. Por eso `<stdalign.h>` define el **macro** `alignof`, que se
|
||||
expande a `_Alignof`. Ahí está tu respuesta fina: `alignof` **es** un macro; `_Alignof` es la
|
||||
palabra clave. En C23 `alignof` pasó a ser palabra clave por derecho propio (y el macro se jubiló).
|
||||
|
||||
Cómo usarlo:
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
#include <stdalign.h> // trae el macro `alignof`
|
||||
|
||||
typedef struct { int a; int b; double c; char d; } Record;
|
||||
|
||||
int main(void) {
|
||||
printf("sizeof(int) = %zu\n", sizeof(int)); // 4
|
||||
printf("alignof(double) = %zu\n", alignof(double)); // 8
|
||||
printf("sizeof(Record) = %zu\n", sizeof(Record)); // 24
|
||||
printf("alignof(Record) = %zu\n", alignof(Record)); // 8
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
> **Detalle de `printf`.** `_Alignof` y `sizeof` devuelven `size_t`: imprimilos con `%zu`, no con
|
||||
> `%d` (si no, el formato no coincide con el tipo y tenés *undefined behavior*).
|
||||
|
||||
> **Para la arena.** Este es el número que le pasás a `ARENA_ALIGN`: `_Alignof(max_align_t)` cubre
|
||||
> cualquier tipo; `_Alignof(Record)` alcanza para los `Record`. Lo importante: la alineación se
|
||||
> **lee del tipo**, no se adivina desde el `sizeof`.
|
||||
|
||||
#### La fórmula, para tontos
|
||||
|
||||
El corazón de todo es redondear **hacia arriba** al múltiplo más cercano:
|
||||
|
||||
```c
|
||||
#define ARENA_ALIGN 8 // alineamos a 8 bytes (potencia de 2)
|
||||
|
||||
// Redondea n hacia arriba al múltiplo de ARENA_ALIGN más cercano.
|
||||
#define ARENA_ALIGN_UP(n) (((n) + (ARENA_ALIGN - 1)) & ~(size_t)(ARENA_ALIGN - 1))
|
||||
```
|
||||
|
||||
La parte `& ~(ARENA_ALIGN - 1)` parece magia negra, pero es solo aritmética de bits. Vamos despacio,
|
||||
con `A = 8`:
|
||||
|
||||
1. **`A - 1 = 7 = 0b0111`.** Es una máscara con los **3 bits de abajo** en 1. Esos 3 bits son justo
|
||||
los que "sobran" dentro de un bloque de 8 (los números 0..7).
|
||||
2. **`n + (A - 1)` = `n + 7`.** Sumar 7 "empuja" el número hacia arriba lo suficiente para que,
|
||||
cualquiera sea su resto dentro del bloque de 8, cruce al próximo límite. Si ya estaba justo en un
|
||||
límite, el `+7` se queda adentro del mismo bloque y da lo mismo.
|
||||
3. **`~(A - 1) = ~0b0111 = 0b...11111000`.** El `~` invierte: ahora esos 3 bits bajos están en 0 y el
|
||||
resto en 1. Hacer `&` con esto **borra el resto**, deja los bits altos intactos.
|
||||
4. **Resultado:** el mayor múltiplo de 8 que es ≤ `n+7`, o sea el **menor múltiplo de 8 ≥ `n`**.
|
||||
|
||||
Tabla, con bits de 4 para que se vea:
|
||||
|
||||
| `n` | `n + 7` | `n + 7` en binario | `& ~7` | resultado |
|
||||
|:---:|:-------:|:------------------:|:------:|:---------:|
|
||||
| 0 | 7 | `0111` | `0000` | **0** |
|
||||
| 1 | 8 | `1000` | `1000` | **8** |
|
||||
| 7 | 14 | `1110` | `1000` | **8** |
|
||||
| 8 | 15 | `1111` | `1000` | **8** |
|
||||
| 9 | 16 | `1 0000` | `1 0000` | **16** |
|
||||
|
||||
Ahí está toda la fórmula: **sumar `A-1` y borrar los bits bajos con `~`**. Nada más.
|
||||
|
||||
> **¿Por qué solo sirve con potencias de 2?** Porque `~(A-1)` solo "borra exactamente los bits del
|
||||
> resto" cuando `A` es potencia de 2. Para `A = 10` esa máscara no existe y habría que dividir con
|
||||
> `/` y `%`. Por suerte **todas** las alineaciones estándar son potencias de 2 (1, 2, 4, 8, 16...),
|
||||
> así que el truco siempre aplica.
|
||||
|
||||
#### Aplicala a la posición, no al tamaño (variante robusta)
|
||||
|
||||
El capítulo redondea el **tamaño** y da por hecho que `offset` ya estaba alineado. Eso alcanza
|
||||
mientras el bloque base esté alineado y todos pidan lo mismo. La versión más honesta **redondea el
|
||||
cursor antes de repartir**, que es lo que de verdad querés: que el hueco *nuevo* empiece alineado.
|
||||
|
||||
```c
|
||||
void *arena_alloc(Arena *a, size_t size) {
|
||||
size_t aligned = ARENA_ALIGN_UP(size); // reservamos un poco más, para alinear
|
||||
if (a->offset + aligned > a->capacity) {
|
||||
// Subo el cursor del offset al múltiplo de 8 más cercano ...
|
||||
size_t aligned = ARENA_ALIGN_UP(a->offset);
|
||||
// ... y recién ahí veo si entra el pedido exacto.
|
||||
if (aligned + size > a->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
void *ptr = a->buffer + a->offset;
|
||||
a->offset += aligned;
|
||||
void *ptr = a->buffer + aligned; // puntero al hueco ya alineado
|
||||
a->offset = aligned + size; // el cursor queda donde termina el dato
|
||||
return ptr;
|
||||
}
|
||||
```
|
||||
|
||||
La parte `& ~(ARENA_ALIGN - 1)` es un truco de bits: como 8 es potencia de 2, "redondear hacia
|
||||
arriba a múltiplo de 8" se hace con una máscara. Es válido **solo porque la alineación es potencia
|
||||
de 2**.
|
||||
Diferencia con la versión anterior (la del capítulo, que redondea el tamaño): esta **desperdicia
|
||||
menos** (usa `size` exacto y solo paga el *padding* necesario antes del bloque) y expresa mejor la
|
||||
idea "alineá la **dirección** donde arranca el dato".
|
||||
|
||||
#### Ojo: el bloque base también manda
|
||||
|
||||
Todo lo anterior asume que `a->buffer` es múltiplo de 8. Como el puntero que devolvés es
|
||||
`base + offset`, si `base` está torcido, **todo** queda torcido y alinear el offset no sirve de nada.
|
||||
|
||||
- `malloc` **garantiza** la alineación de cualquier tipo, así que un bloque pedido con `malloc` es
|
||||
seguro.
|
||||
- En cambio un `unsigned char buffer[4096];` local **puede** quedar alineado a 1, ¡aunque el array
|
||||
sea grande! Si vas a prestar memoria (ejercicio 12.11), forzá la alineación o, mejor, alineá la
|
||||
**dirección absoluta**, que se banca hasta una base torcida:
|
||||
|
||||
```c
|
||||
#include <stdint.h> // uintptr_t
|
||||
|
||||
void *arena_alloc(Arena *a, size_t size) {
|
||||
// Alineo la DIRECCIÓN real (base + offset), no solo el offset.
|
||||
uintptr_t start = (uintptr_t)(a->buffer + a->offset);
|
||||
uintptr_t aligned = (start + (ARENA_ALIGN - 1)) & ~(uintptr_t)(ARENA_ALIGN - 1);
|
||||
size_t pad = aligned - start; // los bytes que "sacrifico" para alinear
|
||||
|
||||
if (a->offset + pad + size > a->capacity) {
|
||||
return NULL;
|
||||
}
|
||||
a->offset += pad + size;
|
||||
return (void *)aligned;
|
||||
}
|
||||
```
|
||||
|
||||
Ese `pad = aligned - start` **es** la respuesta literal a "cómo calculo la posición que debe
|
||||
ocupar": la posición es `aligned`, y el costo de alinear es `pad`. Simple y sin depender de que
|
||||
`base` haya venido alineado.
|
||||
|
||||
#### Lo que te llevás de alineación
|
||||
|
||||
- La alineación es del **tipo**, no del valor ni de la arena.
|
||||
- Para mezclar tipos **no** calculás posiciones: elegís **una** alineación universal
|
||||
(`_Alignof(max_align_t)`) y alineás cada reparto. Un múltiplo de 8 ya es múltiplo de 8, 4, 2 y 1.
|
||||
- La alineación de un struct = la mayor de sus miembros, y **siempre divide a su `sizeof`**. Si el
|
||||
bloque arranca alineado, los miembros caen alineados solos.
|
||||
- La fórmula es `(n + A - 1) & ~(A - 1)`, y solo funciona con `A` potencia de 2.
|
||||
- El bloque **base** también tiene que estar alineado; lo más robusto es alinear la dirección
|
||||
absoluta, no solo el offset.
|
||||
|
||||
### 12.4.2 ¿Y si no entra lo que pedís?
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1405
File diff suppressed because it is too large
Load Diff
+3778
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1077
File diff suppressed because it is too large
Load Diff
+1162
File diff suppressed because it is too large
Load Diff
+2704
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,143 @@
|
||||
#include "arena.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
char* arena_strdup(Arena* ref_arena, const char* s){
|
||||
char* str = (char*) arena_alloc(ref_arena, strlen(s) + 1);
|
||||
if(str == NULL){
|
||||
return NULL;
|
||||
}
|
||||
strcpy(str, s);
|
||||
return str;
|
||||
}
|
||||
|
||||
void* arena_chunk_alloc(Arena* ref_arena, Chunk* chunk, size_t s){
|
||||
size_t aligned = (chunk->offset + (ARENA_MEMORY_ALIGN - 1)) & ~(ARENA_MEMORY_ALIGN -1);
|
||||
if ((aligned + s <= chunk->size)){
|
||||
chunk->offset = aligned;
|
||||
void* start = (void *)(chunk->buffer + chunk->offset);
|
||||
chunk->offset = aligned + s;
|
||||
return start;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Chunk* arena_chunk_create(size_t s){
|
||||
printf("Creating a new chunk of %zu bytes\n", s);
|
||||
Chunk* chunk1 = (Chunk*)malloc(sizeof(Chunk));
|
||||
|
||||
if(chunk1 == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk1->size = s;
|
||||
chunk1->offset = 0;
|
||||
chunk1->next = NULL;
|
||||
|
||||
chunk1->buffer = (unsigned char *)malloc(s);
|
||||
|
||||
if(chunk1->buffer == NULL){
|
||||
perror("Error creando chunk...\n");
|
||||
free(chunk1);
|
||||
chunk1 = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Chunk creado correctamente\n");
|
||||
|
||||
return chunk1;
|
||||
|
||||
}
|
||||
|
||||
void arena_chunk_free(Chunk* chunk){
|
||||
printf("Liberando %zu bytes de memoria\n", chunk->size);
|
||||
if(chunk->buffer != NULL){
|
||||
free(chunk->buffer);
|
||||
chunk->buffer = NULL;
|
||||
}
|
||||
free(chunk);
|
||||
}
|
||||
|
||||
void* arena_alloc(Arena* ref_arena, size_t s){
|
||||
if(ref_arena == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ref_arena->current == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Chunk* current_chunk = ref_arena->current;
|
||||
|
||||
void* ptr = arena_chunk_alloc(ref_arena, current_chunk, s);
|
||||
|
||||
if(ptr == NULL){
|
||||
|
||||
size_t new_size = current_chunk->size * 2;
|
||||
|
||||
if(new_size < s){
|
||||
new_size = s;
|
||||
}
|
||||
|
||||
Chunk *new_chunk = arena_chunk_create(new_size);
|
||||
if(new_chunk == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_chunk->next = new_chunk;
|
||||
new_chunk->next = NULL;
|
||||
ref_arena->current = new_chunk;
|
||||
|
||||
return arena_alloc(ref_arena, s);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
Arena arena_create(size_t s){
|
||||
Arena new_arena = {
|
||||
.current = NULL,
|
||||
.first = NULL
|
||||
};
|
||||
|
||||
Chunk* chunk1 = arena_chunk_create(s);
|
||||
|
||||
if(chunk1 == NULL){
|
||||
perror("Error creando arena\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
new_arena.current = chunk1;
|
||||
new_arena.first = chunk1;
|
||||
|
||||
printf("Arena creada correctamente\n");
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
|
||||
void arena_free(Arena* ref_arena){
|
||||
Chunk* item = ref_arena->first;
|
||||
while (item != NULL) {
|
||||
Chunk *next = item->next;
|
||||
arena_chunk_free(item);
|
||||
item = next;
|
||||
}
|
||||
|
||||
ref_arena->first = NULL;
|
||||
ref_arena->current = NULL;
|
||||
|
||||
printf("Arena liberada\n");
|
||||
}
|
||||
|
||||
void arena_print(Arena* ref_arena){
|
||||
printf("ARENA INFO\n");
|
||||
printf("==========\n");
|
||||
|
||||
printf("first: %p\n", ref_arena->first);
|
||||
printf("next: %p\n", ref_arena->current);
|
||||
|
||||
printf("==========\n");
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ARENA_MEMORY_ALIGN 8
|
||||
|
||||
typedef struct Chunk{
|
||||
size_t size;
|
||||
size_t offset;
|
||||
unsigned char *buffer;
|
||||
struct Chunk *next;
|
||||
}Chunk;
|
||||
|
||||
typedef struct{
|
||||
Chunk *current;
|
||||
Chunk *first;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena*, size_t);
|
||||
void arena_free(Arena*);
|
||||
void arena_print(Arena*);
|
||||
|
||||
Chunk* arena_chunk_create(size_t);
|
||||
void arena_chunk_free(Chunk*);
|
||||
void* arena_chunk_alloc(Arena*, Chunk*, size_t);
|
||||
|
||||
char* arena_strdup(Arena*, const char*);
|
||||
@@ -0,0 +1,90 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct{
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena *, size_t);
|
||||
void arena_destroy(Arena *);
|
||||
|
||||
int main(void){
|
||||
Arena arena = arena_create(13);
|
||||
int *ptrInt1 = (int*)arena_alloc(&arena, sizeof(int));
|
||||
int *ptrInt2 = (int*)arena_alloc(&arena, sizeof(int));
|
||||
float *ptrFloat1 = (float*)arena_alloc(&arena, sizeof(float));
|
||||
char *ptrChar1 = (char*)arena_alloc(&arena, sizeof(char));
|
||||
|
||||
int need = sizeof(int)*2 + sizeof(float) + sizeof(char);
|
||||
|
||||
printf("sizeof int: %d\n", (int)sizeof(int));
|
||||
printf("sizeof float: %d\n", (int)sizeof(float));
|
||||
printf("sizeof char: %d\n", (int)sizeof(char));
|
||||
|
||||
printf("Necesitamos: %d\n", need);
|
||||
|
||||
if(ptrInt1 != NULL){
|
||||
*ptrInt1 = 18;
|
||||
printf("Primer entero: %d\n", *ptrInt1);
|
||||
}
|
||||
if(ptrInt2 != NULL){
|
||||
*ptrInt2 = 27;
|
||||
printf("Segundo entero: %d\n", *ptrInt2);
|
||||
}
|
||||
if(ptrFloat1 != NULL){
|
||||
*ptrFloat1 = 3.1415f;
|
||||
printf("Primer flotante: %f\n", *ptrFloat1);
|
||||
}
|
||||
if(ptrChar1 != NULL){
|
||||
*ptrChar1 = 'L';
|
||||
printf("Primer char: %c\n", *ptrChar1);
|
||||
}
|
||||
|
||||
arena_destroy(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Arena arena_create( size_t bytes){
|
||||
Arena new_arena = {
|
||||
.buffer = NULL,
|
||||
.size = bytes,
|
||||
.offset = 0
|
||||
};
|
||||
|
||||
new_arena.buffer = (unsigned char *)malloc(bytes);
|
||||
|
||||
if(new_arena.buffer == NULL){
|
||||
perror("Error asignando memoria");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
void* arena_alloc(Arena *ref_arena, size_t bytes){
|
||||
|
||||
if(ref_arena->buffer == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ref_arena->offset + bytes > ref_arena->size){
|
||||
perror("Memoria llena\n");
|
||||
return NULL;
|
||||
}
|
||||
void* ptr_ref = ref_arena->buffer + ref_arena->offset;
|
||||
ref_arena->offset += bytes;
|
||||
return ptr_ref;
|
||||
}
|
||||
|
||||
void arena_destroy(Arena *ref_arena){
|
||||
if(ref_arena->buffer != NULL){
|
||||
free(ref_arena->buffer);
|
||||
ref_arena->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,82 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#define FPS 10
|
||||
|
||||
typedef struct{
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena *, size_t);
|
||||
void arena_reset(Arena *);
|
||||
void arena_destroy(Arena *);
|
||||
|
||||
int main(void){
|
||||
srand(time(NULL));
|
||||
Arena arena = arena_create(100);
|
||||
|
||||
for(int i=0; i < FPS; i++){
|
||||
|
||||
int* ptrLeft = arena_alloc(&arena, sizeof(int));
|
||||
|
||||
if(ptrLeft != NULL){
|
||||
*ptrLeft = rand()%FPS;
|
||||
printf("El datos del frame es: %d\n", *ptrLeft);
|
||||
}
|
||||
|
||||
arena_reset(&arena);
|
||||
}
|
||||
|
||||
arena_destroy(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Arena arena_create( size_t bytes){
|
||||
Arena new_arena = {
|
||||
.buffer = NULL,
|
||||
.size = bytes,
|
||||
.offset = 0
|
||||
};
|
||||
|
||||
new_arena.buffer = (unsigned char *)malloc(bytes);
|
||||
|
||||
if(new_arena.buffer == NULL){
|
||||
perror("Error asignando memoria");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
void* arena_alloc(Arena *ref_arena, size_t bytes){
|
||||
|
||||
if(ref_arena->buffer == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ref_arena->offset + bytes > ref_arena->size){
|
||||
perror("Memoria llena\n");
|
||||
return NULL;
|
||||
}
|
||||
void* ptr_ref = ref_arena->buffer + ref_arena->offset;
|
||||
ref_arena->offset += bytes;
|
||||
return ptr_ref;
|
||||
}
|
||||
|
||||
void arena_reset(Arena *ref_arena){
|
||||
ref_arena->offset = 0;
|
||||
}
|
||||
|
||||
void arena_destroy(Arena *ref_arena){
|
||||
if(ref_arena->buffer != NULL){
|
||||
free(ref_arena->buffer);
|
||||
ref_arena->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
+106
@@ -0,0 +1,106 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define FPS 10
|
||||
|
||||
#define ARENA_ALIGN 8
|
||||
|
||||
#define ALLOC_TYPE(REF, TYPE) (TYPE*)arena_alloc(&REF, sizeof(TYPE))
|
||||
|
||||
typedef struct{
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena *, size_t);
|
||||
void arena_reset(Arena *);
|
||||
void arena_destroy(Arena *);
|
||||
bool arena_is_aligned(size_t);
|
||||
|
||||
int main(void){
|
||||
Arena arena = arena_create(32);
|
||||
|
||||
int *test = ALLOC_TYPE(arena, int);
|
||||
|
||||
*test = 5;
|
||||
|
||||
arena_alloc(&arena, 3);
|
||||
|
||||
arena_alloc(&arena, 1);
|
||||
arena_alloc(&arena, 5);
|
||||
arena_alloc(&arena, 9);
|
||||
arena_alloc(&arena, 8);
|
||||
arena_alloc(&arena, 1);
|
||||
|
||||
arena_destroy(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool arena_is_aligned(size_t pos){
|
||||
size_t mask = 7;
|
||||
return (pos & mask) == 0;
|
||||
}
|
||||
|
||||
Arena arena_create( size_t bytes){
|
||||
Arena new_arena = {
|
||||
.buffer = NULL,
|
||||
.size = bytes,
|
||||
.offset = 0
|
||||
};
|
||||
|
||||
new_arena.buffer = (unsigned char *)malloc(bytes);
|
||||
|
||||
if(new_arena.buffer == NULL){
|
||||
perror("Error asignando memoria");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
void* arena_alloc(Arena *ref_arena, size_t bytes){
|
||||
|
||||
if(ref_arena->buffer == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t aligned = ((ref_arena->offset + (size_t)((ARENA_ALIGN - 1))) & ~(ARENA_ALIGN - 1));
|
||||
|
||||
if(aligned + bytes > ref_arena->size){
|
||||
printf("arena_alloc(%d): NULL \n", (int) bytes);
|
||||
return NULL;
|
||||
}
|
||||
void* ptr_ref = ref_arena->buffer + aligned;
|
||||
|
||||
printf("arena_alloc(%d) ", (int) bytes);
|
||||
|
||||
if(arena_is_aligned((size_t)ptr_ref)){
|
||||
printf("aligned: true ");
|
||||
}else{
|
||||
printf("aligned: false ");
|
||||
}
|
||||
|
||||
printf(" base + %d", (int)aligned);
|
||||
printf(" offset: %d -> %d \n", (int)ref_arena->offset, (int)aligned);
|
||||
|
||||
ref_arena->offset = aligned + bytes;
|
||||
|
||||
return ptr_ref;
|
||||
}
|
||||
|
||||
void arena_reset(Arena *ref_arena){
|
||||
ref_arena->offset = 0;
|
||||
}
|
||||
|
||||
void arena_destroy(Arena *ref_arena){
|
||||
if(ref_arena->buffer != NULL){
|
||||
free(ref_arena->buffer);
|
||||
ref_arena->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
+107
@@ -0,0 +1,107 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ARENA_ALIGN 8
|
||||
|
||||
typedef struct{
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena *, size_t);
|
||||
void arena_reset(Arena *);
|
||||
void arena_destroy(Arena *);
|
||||
bool arena_is_aligned(size_t);
|
||||
char* arena_strdup(Arena*, const char *);
|
||||
|
||||
int main(void){
|
||||
Arena arena = arena_create(16);
|
||||
|
||||
char* s1 = arena_strdup(&arena, "arena");
|
||||
char* s2 = arena_strdup(&arena, "hola");
|
||||
char* s3 = arena_strdup(&arena, "x");
|
||||
|
||||
arena_destroy(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char* arena_strdup(Arena* ref_arena, const char *src){
|
||||
char* ref_str = (char*) arena_alloc(ref_arena, strlen(src) + 1);
|
||||
if(ref_str == NULL){
|
||||
perror("No se ha podido reservar memoria para la cadena.");
|
||||
return NULL;
|
||||
}
|
||||
strcpy(ref_str, src);
|
||||
return ref_str;
|
||||
}
|
||||
|
||||
bool arena_is_aligned(size_t pos){
|
||||
size_t mask = 7;
|
||||
return (pos & mask) == 0;
|
||||
}
|
||||
|
||||
Arena arena_create( size_t bytes){
|
||||
Arena new_arena = {
|
||||
.buffer = NULL,
|
||||
.size = bytes,
|
||||
.offset = 0
|
||||
};
|
||||
|
||||
new_arena.buffer = (unsigned char *)malloc(bytes);
|
||||
|
||||
if(new_arena.buffer == NULL){
|
||||
perror("Error asignando memoria");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
void* arena_alloc(Arena *ref_arena, size_t bytes){
|
||||
|
||||
if(ref_arena->buffer == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t aligned = ((ref_arena->offset + (size_t)((ARENA_ALIGN - 1))) & ~(ARENA_ALIGN - 1));
|
||||
|
||||
if(aligned + bytes > ref_arena->size){
|
||||
printf("arena_alloc(%d): NULL \n", (int) bytes);
|
||||
return NULL;
|
||||
}
|
||||
void* ptr_ref = ref_arena->buffer + aligned;
|
||||
|
||||
printf("arena_alloc(%d) ", (int) bytes);
|
||||
|
||||
if(arena_is_aligned((size_t)ptr_ref)){
|
||||
printf("aligned: true ");
|
||||
}else{
|
||||
printf("aligned: false ");
|
||||
}
|
||||
|
||||
printf(" base + %d", (int)aligned);
|
||||
printf(" offset: %d -> %d \n", (int)ref_arena->offset, (int)aligned);
|
||||
|
||||
ref_arena->offset = aligned + bytes;
|
||||
|
||||
return ptr_ref;
|
||||
}
|
||||
|
||||
void arena_reset(Arena *ref_arena){
|
||||
ref_arena->offset = 0;
|
||||
}
|
||||
|
||||
void arena_destroy(Arena *ref_arena){
|
||||
if(ref_arena->buffer != NULL){
|
||||
free(ref_arena->buffer);
|
||||
ref_arena->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
+120
@@ -0,0 +1,120 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ARENA_ALIGN 8
|
||||
|
||||
typedef struct{
|
||||
unsigned char *buffer;
|
||||
size_t size;
|
||||
size_t offset;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena *, size_t);
|
||||
void arena_reset(Arena *);
|
||||
void arena_destroy(Arena *);
|
||||
bool arena_is_aligned(size_t);
|
||||
size_t arena_checkpoint(Arena*);
|
||||
void arena_restore(Arena*, size_t);
|
||||
|
||||
int main(void){
|
||||
Arena arena = arena_create(32);
|
||||
|
||||
size_t cp0 = arena_checkpoint(&arena);
|
||||
int* x = (int*)arena_alloc(&arena, 8);
|
||||
|
||||
*x = 21;
|
||||
|
||||
arena_alloc(&arena, 8);
|
||||
size_t cp1 = arena_checkpoint(&arena);
|
||||
int* tmp = (int*)arena_alloc(&arena, 8);
|
||||
|
||||
arena_restore(&arena, cp1);
|
||||
|
||||
printf("x:%d\n", *x);
|
||||
|
||||
arena_alloc(&arena, 16);
|
||||
|
||||
arena_restore(&arena, cp0);
|
||||
|
||||
arena_alloc(&arena, 32);
|
||||
|
||||
arena_destroy(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arena_restore(Arena* ref_arena, size_t chk){
|
||||
ref_arena->offset = chk;
|
||||
}
|
||||
|
||||
size_t arena_checkpoint(Arena* ref_arena){
|
||||
return ref_arena->offset;
|
||||
}
|
||||
|
||||
bool arena_is_aligned(size_t pos){
|
||||
size_t mask = 7;
|
||||
return (pos & mask) == 0;
|
||||
}
|
||||
|
||||
Arena arena_create( size_t bytes){
|
||||
Arena new_arena = {
|
||||
.buffer = NULL,
|
||||
.size = bytes,
|
||||
.offset = 0
|
||||
};
|
||||
|
||||
new_arena.buffer = (unsigned char *)malloc(bytes);
|
||||
|
||||
if(new_arena.buffer == NULL){
|
||||
perror("Error asignando memoria");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
void* arena_alloc(Arena *ref_arena, size_t bytes){
|
||||
|
||||
if(ref_arena->buffer == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t aligned = ((ref_arena->offset + (size_t)((ARENA_ALIGN - 1))) & ~(ARENA_ALIGN - 1));
|
||||
|
||||
if(aligned + bytes > ref_arena->size){
|
||||
printf("arena_alloc(%d): NULL \n", (int) bytes);
|
||||
return NULL;
|
||||
}
|
||||
void* ptr_ref = ref_arena->buffer + aligned;
|
||||
|
||||
printf("arena_alloc(%d) ", (int) bytes);
|
||||
|
||||
if(arena_is_aligned((size_t)ptr_ref)){
|
||||
printf("aligned: true ");
|
||||
}else{
|
||||
printf("aligned: false ");
|
||||
}
|
||||
|
||||
printf(" base + %d", (int)aligned);
|
||||
printf(" offset: %d -> %d \n", (int)ref_arena->offset, (int)aligned);
|
||||
|
||||
ref_arena->offset = aligned + bytes;
|
||||
|
||||
return ptr_ref;
|
||||
}
|
||||
|
||||
void arena_reset(Arena *ref_arena){
|
||||
ref_arena->offset = 0;
|
||||
}
|
||||
|
||||
void arena_destroy(Arena *ref_arena){
|
||||
if(ref_arena->buffer != NULL){
|
||||
free(ref_arena->buffer);
|
||||
ref_arena->buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
+178
@@ -0,0 +1,178 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define ARENA_MEMORY_ALIGN 8
|
||||
|
||||
typedef struct Chunk{
|
||||
size_t size;
|
||||
size_t offset;
|
||||
unsigned char *buffer;
|
||||
struct Chunk *next;
|
||||
}Chunk;
|
||||
|
||||
typedef struct{
|
||||
Chunk *current;
|
||||
Chunk *first;
|
||||
}Arena;
|
||||
|
||||
Arena arena_create(size_t);
|
||||
void* arena_alloc(Arena*, size_t);
|
||||
void arena_free(Arena*);
|
||||
void arena_print(Arena*);
|
||||
|
||||
Chunk* arena_chunk_create(size_t);
|
||||
void arena_chunk_free(Chunk*);
|
||||
void* arena_chunk_alloc(Arena*, Chunk*, size_t);
|
||||
|
||||
int main(void){
|
||||
|
||||
Arena arena = arena_create(32);
|
||||
|
||||
arena_print(&arena);
|
||||
|
||||
arena_alloc(&arena, 100);
|
||||
|
||||
arena_print(&arena);
|
||||
|
||||
arena_alloc(&arena, 40);
|
||||
|
||||
arena_print(&arena);
|
||||
|
||||
arena_free(&arena);
|
||||
|
||||
arena_print(&arena);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* arena_chunk_alloc(Arena* ref_arena, Chunk* chunk, size_t s){
|
||||
size_t aligned = (chunk->offset + (ARENA_MEMORY_ALIGN - 1)) & ~(ARENA_MEMORY_ALIGN -1);
|
||||
if ((aligned + s <= chunk->size)){
|
||||
chunk->offset = aligned;
|
||||
void* start = (void *)(chunk->buffer + chunk->offset);
|
||||
chunk->offset = aligned + s;
|
||||
return start;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Chunk* arena_chunk_create(size_t s){
|
||||
printf("Creating a new chunk of %zu bytes\n", s);
|
||||
Chunk* chunk1 = (Chunk*)malloc(sizeof(Chunk));
|
||||
|
||||
if(chunk1 == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunk1->size = s;
|
||||
chunk1->offset = 0;
|
||||
chunk1->next = NULL;
|
||||
|
||||
chunk1->buffer = (unsigned char *)malloc(s);
|
||||
|
||||
if(chunk1->buffer == NULL){
|
||||
perror("Error creando chunk...\n");
|
||||
free(chunk1);
|
||||
chunk1 = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("Chunk creado correctamente\n");
|
||||
|
||||
return chunk1;
|
||||
|
||||
}
|
||||
|
||||
void arena_chunk_free(Chunk* chunk){
|
||||
printf("Liberando %zu bytes de memoria\n", chunk->size);
|
||||
if(chunk->buffer != NULL){
|
||||
free(chunk->buffer);
|
||||
chunk->buffer = NULL;
|
||||
}
|
||||
free(chunk);
|
||||
}
|
||||
|
||||
void* arena_alloc(Arena* ref_arena, size_t s){
|
||||
if(ref_arena == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(ref_arena->current == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Chunk* current_chunk = ref_arena->current;
|
||||
|
||||
void* ptr = arena_chunk_alloc(ref_arena, current_chunk, s);
|
||||
|
||||
if(ptr == NULL){
|
||||
|
||||
size_t new_size = current_chunk->size * 2;
|
||||
|
||||
if(new_size < s){
|
||||
new_size = s;
|
||||
}
|
||||
|
||||
Chunk *new_chunk = arena_chunk_create(new_size);
|
||||
if(new_chunk == NULL){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_chunk->next = new_chunk;
|
||||
new_chunk->next = NULL;
|
||||
ref_arena->current = new_chunk;
|
||||
|
||||
return arena_alloc(ref_arena, s);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
Arena arena_create(size_t s){
|
||||
Arena new_arena = {
|
||||
.current = NULL,
|
||||
.first = NULL
|
||||
};
|
||||
|
||||
Chunk* chunk1 = arena_chunk_create(s);
|
||||
|
||||
if(chunk1 == NULL){
|
||||
perror("Error creando arena\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
new_arena.current = chunk1;
|
||||
new_arena.first = chunk1;
|
||||
|
||||
printf("Arena creada correctamente\n");
|
||||
|
||||
return new_arena;
|
||||
|
||||
}
|
||||
|
||||
void arena_free(Arena* ref_arena){
|
||||
Chunk* item = ref_arena->first;
|
||||
while (item != NULL) {
|
||||
Chunk *next = item->next;
|
||||
arena_chunk_free(item);
|
||||
item = next;
|
||||
}
|
||||
|
||||
ref_arena->first = NULL;
|
||||
ref_arena->current = NULL;
|
||||
|
||||
printf("Arena liberada\n");
|
||||
}
|
||||
|
||||
void arena_print(Arena* ref_arena){
|
||||
printf("ARENA INFO\n");
|
||||
printf("==========\n");
|
||||
|
||||
printf("first: %p\n", ref_arena->first);
|
||||
printf("next: %p\n", ref_arena->current);
|
||||
|
||||
printf("==========\n");
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,86 @@
|
||||
#include <stdio.h>
|
||||
#include "../arena-lib/arena.h"
|
||||
#include <string.h>
|
||||
|
||||
typedef struct Persona{
|
||||
char* nombre;
|
||||
int edad;
|
||||
struct Persona* next;
|
||||
}Persona;
|
||||
|
||||
void print_persona(Persona*);
|
||||
|
||||
|
||||
int main(void){
|
||||
|
||||
printf("Alinacion struct Persona: %d\n", (int)_Alignof(Persona));
|
||||
printf("sizeof struct Persona: %d\n", (int)sizeof(Persona));
|
||||
|
||||
Arena arena = arena_create(32);
|
||||
|
||||
char continuar = 'S';
|
||||
|
||||
Persona* first = NULL;
|
||||
Persona* last = NULL;
|
||||
|
||||
do{
|
||||
char input_name[50];
|
||||
printf("Nombre:");
|
||||
if (fgets(input_name, sizeof(input_name), stdin) != NULL) {
|
||||
input_name[strcspn(input_name, "\n")] = '\0';
|
||||
}
|
||||
|
||||
int input_edad = 0;
|
||||
|
||||
printf("Edad:");
|
||||
scanf("%d", &input_edad);
|
||||
printf("\n");
|
||||
|
||||
int c;
|
||||
while ((c = getchar()) != '\n' && c != EOF);
|
||||
|
||||
Persona* p = (Persona*)arena_alloc(&arena, sizeof(Persona));
|
||||
|
||||
if(p == NULL){
|
||||
perror("Ha ocurrido un error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p->nombre = arena_strdup(&arena, input_name);
|
||||
p->edad = input_edad;
|
||||
p->next = NULL;
|
||||
|
||||
if(first == NULL){
|
||||
first = p;
|
||||
}
|
||||
|
||||
if(last != NULL){
|
||||
last->next = p;
|
||||
}
|
||||
|
||||
last = p;
|
||||
|
||||
printf("Cargar mas personas? (S) Continuar, (N): Terminar :");
|
||||
scanf(" %c", &continuar);
|
||||
|
||||
while ((c = getchar()) != '\n' && c != EOF);
|
||||
|
||||
}while((continuar == 'S') || (continuar == 's'));
|
||||
|
||||
printf("Listado de personas cargadas:\n");
|
||||
printf("=============================\n");
|
||||
|
||||
Persona* current = first;
|
||||
while(current != NULL){
|
||||
print_persona(current);
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
arena_free(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_persona(Persona* ref_persona) {
|
||||
printf("%s: tiene %d years\n", ref_persona->nombre, ref_persona->edad);
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
+102
@@ -0,0 +1,102 @@
|
||||
#include "../arena-lib/arena.h"
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum {
|
||||
BIN_OP_SUMA,
|
||||
BIN_OP_RESTA,
|
||||
BIN_OP_MULTIPLY,
|
||||
BIN_OP_DIVISION
|
||||
} BinaryOps;
|
||||
|
||||
typedef enum {
|
||||
NODE_NUMBER,
|
||||
NODE_OPERATION
|
||||
} NodeKind;
|
||||
|
||||
typedef struct Node{
|
||||
union {
|
||||
BinaryOps operation;
|
||||
int number;
|
||||
}value;
|
||||
NodeKind type;
|
||||
struct Node* left;
|
||||
struct Node* right;
|
||||
} Node;
|
||||
|
||||
Node* create_number(Arena* arena_ref, int n){
|
||||
Node* node = (Node*)arena_alloc(arena_ref, sizeof(Node));
|
||||
if(node == NULL){
|
||||
return NULL;
|
||||
}
|
||||
node->type = NODE_NUMBER;
|
||||
node->value.number = n;
|
||||
node->left = NULL;
|
||||
node->right = NULL;
|
||||
return node;
|
||||
}
|
||||
|
||||
Node* create_operation(Arena* ref_arena, BinaryOps op, Node* l, Node* r){
|
||||
Node* node = (Node*)arena_alloc(ref_arena, sizeof(Node));
|
||||
if(node == NULL){
|
||||
return NULL;
|
||||
}
|
||||
node->type = NODE_OPERATION;
|
||||
node->value.operation = op;
|
||||
node->left = l;
|
||||
node->right = r;
|
||||
return node;
|
||||
}
|
||||
|
||||
int node_compute(Node* node){
|
||||
if(node->type == NODE_OPERATION){
|
||||
int r1 = node_compute(node->left);
|
||||
int r2 = node_compute(node->right);
|
||||
int result = 0;
|
||||
switch (node->value.operation) {
|
||||
case BIN_OP_SUMA:
|
||||
result = r1 + r2;
|
||||
break;
|
||||
case BIN_OP_RESTA:
|
||||
result = r1 - r2;
|
||||
break;
|
||||
case BIN_OP_MULTIPLY:
|
||||
result = r1 * r2;
|
||||
break;
|
||||
case BIN_OP_DIVISION:
|
||||
result = (r2 != 0) ? r1 / r2 : 0;
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return node->value.number;
|
||||
}
|
||||
|
||||
int main(void){
|
||||
|
||||
Arena arena = arena_create(32);
|
||||
|
||||
printf("Memory struct information\n");
|
||||
printf("=========================\n");
|
||||
printf("sizeof(Node):%zu\n", sizeof(Node));
|
||||
printf("align(Node): %zu\n", _Alignof(Node));
|
||||
|
||||
//Creamos el arbol para 3 + (4 - 1)
|
||||
Node* t1 = create_number(&arena, 3);
|
||||
Node* t21 = create_number(&arena, 4);
|
||||
Node* t22 = create_number(&arena, 1);
|
||||
Node* t2 = create_operation(&arena, BIN_OP_RESTA, t21, t22);
|
||||
Node* root = create_operation(&arena, BIN_OP_SUMA, t1, t2);
|
||||
|
||||
printf("Node compute\n");
|
||||
printf("============\n");
|
||||
|
||||
printf("result: %d\n", node_compute(root));
|
||||
|
||||
arena_free(&arena);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,73 @@
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include<stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include<unistd.h>
|
||||
#include<getopt.h>
|
||||
|
||||
|
||||
static struct option option_args[] = {
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{"verbose", no_argument, 0, 'v' },
|
||||
{"output", required_argument, 0, 'o' },
|
||||
{"max", required_argument, 0, 'm' },
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
void print_usage(char* arg){
|
||||
fprintf(stdout, "Uso: %s\n", arg);
|
||||
fprintf(stdout, "[--help]\n");
|
||||
fprintf(stdout, "[--verbose]\n");
|
||||
fprintf(stdout, "[--output <archivo>]\n");
|
||||
fprintf(stdout, "[--max <num>]\n");
|
||||
fprintf(stdout, "[posicionales...]\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]){
|
||||
|
||||
printf("argv[0]: %s\n", argv[0]);
|
||||
|
||||
int opt;
|
||||
int opt_index = 0;
|
||||
|
||||
while((opt = getopt_long(argc, argv, "hvo:m:", option_args, &opt_index)) != -1){
|
||||
switch (opt){
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(0);
|
||||
break;
|
||||
case 'v':
|
||||
fprintf(stdout, "Modo verbose: ON\n");
|
||||
break;
|
||||
case 'o':
|
||||
fprintf(stdout, "Output: %s\n", optarg);
|
||||
break;
|
||||
case 'm':
|
||||
errno = 0;
|
||||
char* errorptr = NULL;
|
||||
long maximo = strtol(optarg, &errorptr, 10);
|
||||
if( (errno == EINVAL)
|
||||
|| (errno == ERANGE)
|
||||
|| (*errorptr != 0)
|
||||
|| (maximo < INT_MIN)
|
||||
|| (maximo > INT_MAX)
|
||||
){
|
||||
fprintf(stderr, "--max debe ser un numero entero valido.\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Maximo:%ld\n", maximo);
|
||||
break;
|
||||
case '?':
|
||||
print_usage(argv[0]);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "Posicionales:\n");
|
||||
for(int i = optind; i < argc; i++){
|
||||
fprintf(stdout, "%s\n", argv[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Enunciado del Ejercicio: Modificación de Arreglos mediante Aritmética de Punteros
|
||||
*
|
||||
* Objetivo:
|
||||
* Practicar el manejo de punteros y su relación con los arreglos estáticos en el lenguaje C,
|
||||
* aplicando aritmética de punteros para recorrer y modificar los elementos almacenados en memoria.
|
||||
*
|
||||
* Descripción:
|
||||
*
|
||||
* Escribe un programa completo en C que realice las siguientes tareas:
|
||||
*
|
||||
* Declaración e Inicialización:
|
||||
*
|
||||
* Declara un arreglo estático de 5 enteros (int) e inicialízalo
|
||||
* con valores arbitrarios de tu elección (por ejemplo: 5, 10, 15, 20, 25).
|
||||
*
|
||||
* Declara un puntero a entero (int *ptr) que apunte al inicio del arreglo.
|
||||
*
|
||||
* Procesamiento con Aritmética de Punteros:
|
||||
*
|
||||
* Utiliza un bucle (for o el de tu preferencia) para recorrer el arreglo únicamente mediante
|
||||
* aritmética de punteros y el operador de indirección en la forma *(ptr + i) (o incrementando el puntero directamente).
|
||||
*
|
||||
* Dentro del bucle, suma 10 al valor actual almacenado en cada posición del arreglo.
|
||||
*
|
||||
* Salida por Consola:
|
||||
*
|
||||
* Muestra en pantalla los valores del arreglo antes y después de aplicar la modificación
|
||||
* para verificar que el cambio se realizó correctamente en la memoria del arreglo original.
|
||||
*
|
||||
* Restricciones:
|
||||
*
|
||||
* Está prohibido utilizar la notación de corchetes (arreglo[i]) para acceder o modificar
|
||||
* los elementos del arreglo dentro del bucle. Debes usar estrictamente la sintaxis de punteros (*(ptr + i)).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define V_LENGTH 5
|
||||
|
||||
void print_arr(int *);
|
||||
|
||||
int main(void){
|
||||
int v1[V_LENGTH] = {5, 10, 15, 20, 25};
|
||||
int* ptr_v1 = v1;
|
||||
print_arr(ptr_v1);
|
||||
for(int i=0; i<V_LENGTH; i++){
|
||||
*(ptr_v1 + i) += 10;
|
||||
}
|
||||
print_arr(ptr_v1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_arr(int *arr){
|
||||
printf("Array: ");
|
||||
for(int i = 0; i < V_LENGTH; i++){
|
||||
printf(" %d,", *(arr + i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void) {
|
||||
|
||||
unsigned char flags = 0b0000010;
|
||||
|
||||
unsigned char FLAG_A = 1u << 0;
|
||||
unsigned char FLAG_B = 1u << 1;
|
||||
|
||||
printf("El FLAG_A es: %08b\n", FLAG_A);
|
||||
printf("El FLAG_B es: %08b\n", FLAG_B);
|
||||
|
||||
// encender ambos.
|
||||
flags = (FLAG_A | FLAG_B);
|
||||
|
||||
if (flags & (FLAG_A)) {
|
||||
printf("El flag A esta encendido\n");
|
||||
}
|
||||
|
||||
if (flags & (FLAG_B)) {
|
||||
printf("El flag B esta encendido\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* El objetivo es escribir un codigo donde falle al intentar modificar el contenido de un puntero
|
||||
* y tambien falle al intentar modificar a donde apunta otro puntero.
|
||||
*/
|
||||
|
||||
|
||||
int main(void){
|
||||
int sensor_temp = 25;
|
||||
int sensor_humedad = 60;
|
||||
int ipa = 192;
|
||||
int ipb = 168;
|
||||
const int *ptr_lectura = &sensor_temp;
|
||||
int * const ptr_config = &ipa;
|
||||
|
||||
ptr_lectura = &sensor_humedad;
|
||||
|
||||
//No debo poder modificar el valor del sensor mediante el puntero.
|
||||
*ptr_lectura = 44;
|
||||
|
||||
*ptr_config = 10;
|
||||
|
||||
//No debo poder cambiar a donde apunta el puntero ptr_config.
|
||||
ptr_config = &ipb;
|
||||
return 0;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
Hola, mundo
|
||||
C es genial
|
||||
Fin
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int count_chars(char *rline);
|
||||
void fix_path(char *rpath);
|
||||
|
||||
int main(void) {
|
||||
char file_path[128];
|
||||
int char_count = 0, lines_count = 0;
|
||||
FILE *fp;
|
||||
|
||||
printf("Path:");
|
||||
if (fgets(file_path, 128, stdin) == NULL) {
|
||||
perror("fgets");
|
||||
return 1;
|
||||
}
|
||||
printf("\nLeyendo archivo: %s", file_path);
|
||||
|
||||
fix_path(file_path);
|
||||
|
||||
fp = fopen(file_path, "r");
|
||||
|
||||
if (fp == NULL) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char lbuffer[256];
|
||||
|
||||
while ((fgets(lbuffer, 256, fp)) != NULL) {
|
||||
char_count += count_chars(lbuffer);
|
||||
lines_count++;
|
||||
}
|
||||
|
||||
printf("Caracteres: %d\n", char_count);
|
||||
printf("Lineas: %d\n", lines_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count_chars(char *rline) { return strlen(rline) - 1; }
|
||||
|
||||
void fix_path(char *rpath) {
|
||||
for (int i = 0; i < 128; i++) {
|
||||
if (rpath[i] == '\n') {
|
||||
rpath[i] = '\0';
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
ESTE ES UN ARCHIVO
|
||||
DE PRUEBAS DONDE VAMOS A EVALUAR COMO
|
||||
SE COPIA ESTE CORREO HORACIODRS@GMAIL.COM
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
char *src = "src-test.txt";
|
||||
char *dst = "dst-test.txt";
|
||||
|
||||
if (argc == 3) {
|
||||
src = strdup(argv[1]);
|
||||
dst = strdup(argv[2]);
|
||||
} else {
|
||||
fprintf(stderr, "Argumentos invalidos.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *fpsrc, *fpdst;
|
||||
|
||||
fpsrc = fopen(src, "r");
|
||||
|
||||
if (fpsrc == NULL) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fpdst = fopen(dst, "w");
|
||||
|
||||
if (fpdst == NULL) {
|
||||
perror("fopen");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int c;
|
||||
while ((c = fgetc(fpsrc)) && c != EOF) {
|
||||
fputc(toupper(c), fpdst);
|
||||
}
|
||||
|
||||
fclose(fpsrc);
|
||||
fclose(fpdst);
|
||||
|
||||
printf("Archivo duplicado en mayusculas con exito en: %s\n", dst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
Este es un archivo
|
||||
de pruebas donde vamos a evaluar como
|
||||
se copia este correo horaciodrs@gmail.com
|
||||
Binary file not shown.
@@ -0,0 +1,166 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_error.h>
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_log.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include <SDL2/SDL_video.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void render_image(SDL_Renderer *ref_renderer, unsigned char *data,
|
||||
unsigned long w, unsigned long h);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Argumentos invalidos\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *fname;
|
||||
|
||||
fname = strdup(argv[1]);
|
||||
|
||||
if (fname == NULL) {
|
||||
perror("strdup");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *pfile = fopen(fname, "rb");
|
||||
|
||||
if (pfile == NULL) {
|
||||
perror("fopen");
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *header = NULL;
|
||||
|
||||
header = malloc(sizeof(uint8_t) * 3);
|
||||
|
||||
printf("El sizeof de header es: %d\n", (int)sizeof(header));
|
||||
|
||||
if (fread(header, sizeof(uint8_t) * 2, 1, pfile) == 0) {
|
||||
perror("fread");
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
header[3] = '\0';
|
||||
|
||||
int w, h, s;
|
||||
|
||||
if (fscanf(pfile, " %d %d %d", &w, &h, &s) != 3) {
|
||||
fprintf(stderr, "Error leyendo las caracteristicas de la imagen.\n");
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Header readed: %s\n", (unsigned char *)header);
|
||||
fprintf(stdout,
|
||||
"Las dimensiones son %dx%d pixeles y una escala maxima de color de "
|
||||
"%d\n",
|
||||
w, h, s);
|
||||
|
||||
// consumo un caracter mas y queda listo para leer los datos de los pixeles.
|
||||
fgetc(pfile);
|
||||
|
||||
unsigned char *data = NULL;
|
||||
unsigned long pixel_count = w * h;
|
||||
|
||||
data = malloc(sizeof(data) * pixel_count * 3);
|
||||
|
||||
if (data == NULL) {
|
||||
perror("malloc");
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned long readed =
|
||||
fread(data, sizeof(unsigned char) * 3, pixel_count, pfile);
|
||||
|
||||
fprintf(stdout, "%zu pixeles leidos de %zu\n", readed, pixel_count);
|
||||
|
||||
if (readed != pixel_count) {
|
||||
fprintf(stderr, "Error leyendo datos del archivo\n");
|
||||
free(data);
|
||||
fclose(pfile);
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
perror("SLD_Init");
|
||||
free(data);
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_Window *window =
|
||||
SDL_CreateWindow("Visor de imagenes", SDL_WINDOWPOS_CENTERED,
|
||||
SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_SHOWN);
|
||||
|
||||
if (window == NULL) {
|
||||
SDL_Log("SLD_WINDOW: %s", SDL_GetError());
|
||||
SDL_Quit();
|
||||
free(data);
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(
|
||||
window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
|
||||
if (!renderer) {
|
||||
SDL_Log("No se pudo crear el renderizador: %s", SDL_GetError());
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
free(data);
|
||||
fclose(pfile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool running = true;
|
||||
SDL_Event ev;
|
||||
while (running) {
|
||||
while (SDL_PollEvent(&ev)) {
|
||||
if (ev.type == SDL_QUIT) {
|
||||
running = 0; // Si hacen clic en la "X", salimos
|
||||
}
|
||||
if (ev.type == SDL_KEYDOWN) {
|
||||
// Si presionan Escape, salimos
|
||||
if (ev.key.keysym.sym == SDLK_ESCAPE) {
|
||||
running = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_RenderClear(renderer);
|
||||
render_image(renderer, data, w, h);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_Quit();
|
||||
|
||||
free(data);
|
||||
fclose(pfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void render_image(SDL_Renderer *ref_renderer, unsigned char *rdata,
|
||||
unsigned long int w, unsigned long h) {
|
||||
|
||||
unsigned long offset = 0;
|
||||
for (unsigned long cury = 0; cury < h; cury++) {
|
||||
for (unsigned long curx = 0; curx < w; curx++) {
|
||||
uint8_t r = *(rdata + offset++);
|
||||
uint8_t g = *(rdata + offset++);
|
||||
uint8_t b = *(rdata + offset++);
|
||||
|
||||
SDL_SetRenderDrawColor(ref_renderer, r, g, b, 255);
|
||||
SDL_RenderDrawPoint(ref_renderer, curx, cury);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
Se encontraron 3 registros invalidos.
|
||||
Iniciando reporte.
|
||||
Procesando 128 registros.
|
||||
Reporte generado correctamente.
|
||||
@@ -0,0 +1 @@
|
||||
Se encontraron 3 registros invalidos.
|
||||
@@ -0,0 +1,7 @@
|
||||
Permissions Size User Date Modified Name
|
||||
.rw-r--r-- 38 horacio 28 Oct 10:58 errores.txt
|
||||
.rw-r--r-- 0 horacio 28 Oct 11:07 listado.txt
|
||||
.rw-r--r-- 271 horacio 28 Oct 10:55 main.c
|
||||
.rwxr-xr-x 16k horacio 28 Oct 10:56 programa
|
||||
.rw-r--r-- 24 horacio 28 Oct 11:04 salida.txt
|
||||
.rw-r--r-- 19 horacio 28 Oct 11:00 test.txt
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <stdio.h>
|
||||
int main(void){
|
||||
fprintf(stdout, "Iniciando reporte.\n");
|
||||
fprintf(stdout, "Procesando 128 registros.\n");
|
||||
fprintf(stdout, "Reporte generado correctamente.\n");
|
||||
|
||||
fprintf(stderr, "Se encontraron 3 registros invalidos.\n");
|
||||
return 1;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
Iniciando reporte.
|
||||
Procesando 128 registros.
|
||||
Reporte generado correctamente.
|
||||
@@ -0,0 +1,2 @@
|
||||
test
|
||||
segunda linea
|
||||
@@ -0,0 +1,16 @@
|
||||
#include <stdio.h>
|
||||
int main(void){
|
||||
int c, count = 0, countbr = 0;
|
||||
|
||||
while((c = getchar()) != EOF){
|
||||
if(c == '\n'){
|
||||
countbr++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
fprintf(stdout, "Se leyeron %d bytes\n", count);
|
||||
fprintf(stdout, "Se leyeron %d <br> \n", countbr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
este es un archivo
|
||||
de texto
|
||||
@@ -0,0 +1,42 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int count_words(char*);
|
||||
|
||||
int main(void){
|
||||
|
||||
char buffer[50];
|
||||
int total_words = 0;
|
||||
|
||||
while((fgets(buffer, sizeof(buffer), stdin)) != NULL){
|
||||
total_words += count_words(buffer);
|
||||
}
|
||||
|
||||
printf("El total de palabras es: %d\n", total_words);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count_words(char* line){
|
||||
int palabras = 0;
|
||||
bool hay_espacio = false;
|
||||
|
||||
printf("line: %s", line);
|
||||
|
||||
if((line[0] != ' ') && strlen(line) > 0){
|
||||
palabras++;
|
||||
}
|
||||
|
||||
for(int i = 0; i < strlen(line); i++){
|
||||
if(line[i] == ' '){
|
||||
hay_espacio = true;
|
||||
}
|
||||
|
||||
if((line[i] != ' ') && (line[i] != '\n') && (hay_espacio)){
|
||||
palabras++;
|
||||
hay_espacio = false;
|
||||
}
|
||||
}
|
||||
return palabras;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,32 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void clear_buffer(void);
|
||||
|
||||
int main(void) {
|
||||
int edad = 0;
|
||||
char buffer[20];
|
||||
|
||||
printf("Ingresar una edad:");
|
||||
scanf("%d", &edad);
|
||||
|
||||
clear_buffer();
|
||||
|
||||
printf("\nIngresar un nombre:");
|
||||
|
||||
fgets(buffer, 20, stdin);
|
||||
|
||||
printf("\n====================================\n");
|
||||
printf("La edad ingresada es: %d \n", edad);
|
||||
|
||||
printf("El nombre ingresado es: %s \n", buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear_buffer(void) {
|
||||
|
||||
int c = 0;
|
||||
|
||||
while ((c = getchar()) && c != '\n' && c != EOF) {
|
||||
}
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,50 @@
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct Document {
|
||||
int id;
|
||||
char active;
|
||||
char name[50];
|
||||
} Document;
|
||||
|
||||
void leer_id(Document *);
|
||||
void leer_nombre(Document *);
|
||||
void imprimir(Document *);
|
||||
|
||||
int main(void) {
|
||||
|
||||
Document hdr;
|
||||
|
||||
leer_id(&hdr);
|
||||
leer_nombre(&hdr);
|
||||
imprimir(&hdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void leer_id(Document *ref) {
|
||||
int rid = -1;
|
||||
char c;
|
||||
char ractive = 'n';
|
||||
printf("Entrada:");
|
||||
scanf("%d", &rid);
|
||||
ref->id = rid;
|
||||
while ((c = getchar()) && c != '\n' && c != EOF) {
|
||||
if ((c == 's') || (c == 'S')) {
|
||||
ractive = 's';
|
||||
}
|
||||
}
|
||||
ref->active = ractive;
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void leer_nombre(Document *ref) {
|
||||
printf("Nombre:");
|
||||
fgets(ref->name, 50, stdin);
|
||||
}
|
||||
|
||||
void imprimir(Document *ref) {
|
||||
printf("=======================================\n");
|
||||
printf("ID: %d \n", ref->id);
|
||||
printf("ACTIVE: %c \n", ref->active);
|
||||
printf("NOMBRE: %s \n", ref->name);
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,13 @@
|
||||
#include "stringv.h"
|
||||
#include <stdio.h>
|
||||
int main(void) {
|
||||
StringView s1 = sv_from_cstr("Hola mundo con string view");
|
||||
StringView s2 = sv_from_cstr("😊");
|
||||
StringView last = sv_right(&s1, 4);
|
||||
|
||||
printf("El string view contiene: %s\n", s2.text);
|
||||
printf("El length es: %zu\n", s2.lenght);
|
||||
|
||||
printf("last tiene:%.*s\n", (int)last.lenght, last.text);
|
||||
return 0;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,60 @@
|
||||
#include "stringv.h"
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* @brief Create a string view from a const char* and set their lenght
|
||||
*
|
||||
* @details This string view provides a view of a string. It does not allocate
|
||||
* memory, therefore, it lives only while the source is alive. The
|
||||
* lenght is a bytes number of the string. It does not represents the number of
|
||||
* characters.
|
||||
*
|
||||
* @param str pointer from the original string. It can be NULL.
|
||||
*
|
||||
* @return a StringView with the view of original string with corresponding
|
||||
* lenght.
|
||||
*/
|
||||
|
||||
#define STRING_VIEW_NULL (StringView){.text = NULL, .lenght = 0}
|
||||
|
||||
StringView sv_from_cstr(const char *str) {
|
||||
if (str == NULL) {
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
return (StringView){.text = (char *)str, .lenght = strlen(str)};
|
||||
}
|
||||
|
||||
StringView sv_left(const StringView *sv, size_t l) {
|
||||
if (sv == NULL) {
|
||||
perror("sv_left: pointer is NULL\n");
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
if (sv->text == NULL) {
|
||||
perror("sv_left: text pointer is NULL\n");
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
if (sv->lenght < l) {
|
||||
perror("sv_left: text length is less than specified length\n");
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
return (StringView){.text = sv->text, .lenght = l};
|
||||
}
|
||||
|
||||
StringView sv_right(const StringView *sv, size_t r) {
|
||||
if (sv == NULL) {
|
||||
perror("sv_right: pointer is NULL\n");
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
if (sv->text == NULL) {
|
||||
perror("sv_right: text pointer is NULL\n");
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
if (sv->lenght < r) {
|
||||
perror("sv_right: text length is less than specified length\n");
|
||||
return STRING_VIEW_NULL;
|
||||
}
|
||||
size_t nlength = sv->lenght - r;
|
||||
return (StringView){.text = sv->text + nlength, .lenght = r};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef STRING_VIEW_H
|
||||
#define STRING_VIEW_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct StringView {
|
||||
char *text;
|
||||
size_t lenght;
|
||||
} StringView;
|
||||
|
||||
StringView sv_from_cstr(const char *);
|
||||
StringView sv_left(const StringView *sv, size_t l);
|
||||
StringView sv_right(const StringView *sv, size_t l);
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* EJERCICIO DE LENGUAJE C: STRUCTS Y PUNTEROS
|
||||
*
|
||||
* 1. Define una struct llamada Coordenada que contenga dos campos enteros: x e y.
|
||||
* 2. Implementa una función constructora llamada Coordenada* crear_coordenada(int x, int y) que:
|
||||
* - Reserve memoria dinámicamente utilizando malloc para una nueva estructura Coordenada.
|
||||
* - Verifique si la reserva de memoria fue exitosa.
|
||||
* - Inicialice sus campos x e y con los valores pasados como parámetros.
|
||||
* - Devuelva el puntero a la estructura creada.
|
||||
* 3. En la función main:
|
||||
* - Utiliza la función constructora para crear una coordenada.
|
||||
* - Muestra por pantalla los valores iniciales utilizando el operador flecha (->).
|
||||
* - Modifica los valores de los campos de la estructura utilizando también el operador flecha (->).
|
||||
* - Muestra los nuevos valores por pantalla.
|
||||
* - Libera la memoria reservada dinámicamente utilizando free para evitar pérdidas de memoria.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
typedef struct{
|
||||
int x;
|
||||
int y;
|
||||
}Coordenada;
|
||||
|
||||
Coordenada* crear_coordenada(int x, int y);
|
||||
void modificar_coordenada(Coordenada**, int x, int y);
|
||||
void imprimir_coordenada(Coordenada**);
|
||||
|
||||
int main(void){
|
||||
|
||||
Coordenada* cord = crear_coordenada(10, 20);
|
||||
|
||||
imprimir_coordenada(&cord);
|
||||
modificar_coordenada(&cord, 30, 40);
|
||||
imprimir_coordenada(&cord);
|
||||
|
||||
free(cord);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Coordenada* crear_coordenada(int x, int y){
|
||||
Coordenada* new_cord = malloc(sizeof(Coordenada));
|
||||
if(new_cord == NULL){
|
||||
perror("No se pudo crear la coordenada\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
new_cord->x = x;
|
||||
new_cord->y = y;
|
||||
|
||||
return new_cord;
|
||||
}
|
||||
|
||||
void modificar_coordenada(Coordenada** cord_address, int x, int y){
|
||||
if((*cord_address) == NULL){
|
||||
perror("No se ha proporcionado una coordenada para modificar\n");
|
||||
exit(1);
|
||||
}
|
||||
(*cord_address)->x = x;
|
||||
(*cord_address)->y = y;
|
||||
}
|
||||
|
||||
void imprimir_coordenada(Coordenada** a){
|
||||
printf("Coordenada(%d, %d);\n", (*a)->x, (*a)->y);
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,92 @@
|
||||
/*******************************************************************************
|
||||
* TRABAJO PRÁCTICO / EJERCICIO INTEGRADOR: GESTIÓN DE PUNTEROS Y ESTRUCTURAS
|
||||
*
|
||||
* OBJETIVO:
|
||||
* El propósito de este ejercicio es consolidar el manejo de estructuras,
|
||||
* aritmética de punteros, indirección y diseño de funciones conpaso por referencia
|
||||
* en el lenguaje C, evitando el uso de código resuelto y enfocándose en la
|
||||
* especificación formal del problema.
|
||||
*
|
||||
* CONSIGNA:
|
||||
* Desarrolle un programa en Lenguaje C que cumpla rigurosamente con los
|
||||
* siguientes requerimientos técnicos y estructurales:
|
||||
*
|
||||
* 1. Definición del Tipo de Dato (Struct con Punteros Internos):
|
||||
* - Defina una estructura denominada `Persona` que contenga dos campos:
|
||||
* * Un puntero a caracteres (`char *nombre`) destinado a almacenar
|
||||
* dinámicamente o mediante literales la identificación de la persona.
|
||||
* * Un número entero (`int edad`) que represente los años de la persona.
|
||||
*
|
||||
* 2. Estructura de Almacenamiento (Arreglo de Estructuras):
|
||||
* - En la función principal (`main`), declare un arreglo estático con
|
||||
* capacidad exactamente para 3 elementos de tipo `Persona`.
|
||||
* - Inicialice cada uno de los elementos del arreglo asignando valores
|
||||
* válidos tanto para el puntero `nombre` como para la `edad`.
|
||||
* - Implemente una función específica (cuya firma y diseño quedan a su cargo)
|
||||
* que reciba como parámetro el puntero al inicio del arreglo de estructuras
|
||||
* y su tamaño, y se encargue de recorrerlo sistemáticamente para
|
||||
* imprimir en la consola los datos de todos sus elementos.
|
||||
*
|
||||
* 3. Encapsulamiento y Modificación (Funciones Modificadoras / Setters):
|
||||
* - Escriba una función modular de tipo `void` llamada `cambiar_edad`
|
||||
* cuya firma obligatoria sea:
|
||||
* `void cambiar_edad(Persona *p, int nueva_edad)`
|
||||
* - Dicha función debe recibir un puntero a una estructura `Persona`
|
||||
* para actualizar el campo correspondiente de forma segura mediante
|
||||
* el operador de indirección adecuado, reflejando el cambio en el ámbito
|
||||
* del programa principal.
|
||||
*
|
||||
* 4. Pautas de Entrega y Validación:
|
||||
* - El programa debe compilar sin errores ni advertencias bajo un estándar
|
||||
* moderno de C (por ejemplo, -std=c11 o superior).
|
||||
* - No se deben utilizar variables globales; toda la comunicación entre
|
||||
* funciones debe realizarse mediante parámetros y punteros.
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define P_LENGTH 3
|
||||
|
||||
typedef struct{
|
||||
char* nombre;
|
||||
int edad;
|
||||
}Persona;
|
||||
|
||||
void listar_personas(Persona*, int length);
|
||||
void cambiar_edad(Persona *p, int nueva_edad);
|
||||
|
||||
int main(void){
|
||||
|
||||
Persona personas[P_LENGTH] = {
|
||||
{
|
||||
.nombre = "Horacio",
|
||||
.edad = 43
|
||||
},
|
||||
{
|
||||
.nombre = "Raquel",
|
||||
.edad = 44
|
||||
}, {
|
||||
.nombre = "Luna",
|
||||
.edad = 15
|
||||
}
|
||||
};
|
||||
|
||||
listar_personas(personas, P_LENGTH);
|
||||
cambiar_edad(personas, 21);
|
||||
cambiar_edad(personas+1, 22);
|
||||
cambiar_edad(personas+2, -5);
|
||||
listar_personas(personas, P_LENGTH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void listar_personas(Persona* p, int length){
|
||||
for(int i=0; i < length; i++){
|
||||
printf("%s \t %d \n", (p+i)->nombre, (p+i)->edad);
|
||||
}
|
||||
}
|
||||
|
||||
void cambiar_edad(Persona *p, int nueva_edad){
|
||||
p->edad = nueva_edad;
|
||||
}
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,347 @@
|
||||
/* =========================================================================
|
||||
* PROYECTO: Sistema de Registro y Telemetría para el Nanosatélite "Andrómeda-1"
|
||||
* -------------------------------------------------------------------------
|
||||
* CONTEXTO:
|
||||
* La Agencia Espacial Experimental está desarrollando el software de a bordo
|
||||
* para su próximo nanosatélite. El sistema necesita gestionar memoria de
|
||||
* forma dinámica y eficiente debido a los recursos limitados del microcontrolador
|
||||
* y a la naturaleza impredecible de las ráfagas de datos en órbita.
|
||||
*
|
||||
* OBJETIVO:
|
||||
* Diseñar e implementar un programa en lenguaje C que resuelva los siguientes
|
||||
* módulos de gestión de memoria dinámica requeridos por la estación de tierra:
|
||||
*
|
||||
* 1. Vector Dinámico Básico (Canales de Sensores):
|
||||
* Pide al operador un número N de canales activos, utiliza malloc para
|
||||
* reservar un arreglo de enteros con las lecturas iniciales, muéstralo en
|
||||
* consola y libera correctamente la memoria con free al terminar.
|
||||
*
|
||||
* 2. Cadenas Dinámicas (Identificadores de Misión):
|
||||
* Escribe una función que reciba una cadena estática (char *) con el nombre
|
||||
* de código del satélite, calcule su longitud exacta, reserve espacio
|
||||
* dinámicamente con malloc, copie la cadena y devuelva el nuevo puntero
|
||||
* dinámico para ser registrado en los logs del sistema.
|
||||
*
|
||||
* 3. Estructura Dinámica (Buffer de Archivos de Telemetría):
|
||||
* Define una struct Archivo que contenga dos campos: size_t tamano y
|
||||
* uint8_t *datos. Escribe una función que reciba el tamaño deseado y reserve
|
||||
* memoria dinámicamente tanto para la estructura en sí como para su búfer
|
||||
* interno de datos binarios.
|
||||
*
|
||||
* 4. Redimensionamiento con realloc (Stream de Datos en Tiempo Real):
|
||||
* Crea una rutina que lea números enteros (paquetes de telemetría) desde
|
||||
* la consola de forma indefinida hasta una condición de parada. Almacénalos
|
||||
* en un arreglo dinámico que duplique su tamaño cada vez que se llene
|
||||
* utilizando realloc para optimizar el almacenamiento.
|
||||
*
|
||||
* 5. Estructuras Anidadas Dinámicas (Subsistemas del Satélite):
|
||||
* Crea una estructura principal (por ejemplo, MisionEspacial) que contenga
|
||||
* un puntero a un arreglo dinámico de subestructuras (representando varios
|
||||
* subsistemas como energía, propulsión y comunicación). Asegúrate de
|
||||
* implementar un protocolo estricto de liberación en orden inverso
|
||||
* (primero las subestructuras internas y sus recursos, luego el arreglo
|
||||
* principal) para evitar fugas de memoria (memory leaks) críticas en órbita.
|
||||
*
|
||||
* REQUISITOS TÉCNICOS:
|
||||
* - Uso obligatorio de las funciones de <stdlib.h> (malloc, realloc, free).
|
||||
* - Validación de punteros (verificar que no sean NULL tras cada reserva).
|
||||
* - Código limpio, modularizado en funciones y bien comentado.
|
||||
* ========================================================================= */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct{
|
||||
size_t size;
|
||||
uint8_t *datos;
|
||||
}TelemetryFile;
|
||||
|
||||
typedef struct{
|
||||
TelemetryFile base;
|
||||
size_t offset;
|
||||
}TelemetryArray;
|
||||
|
||||
typedef struct{
|
||||
int n_chanels;
|
||||
int* chanels;
|
||||
TelemetryFile* telemetry_file;
|
||||
TelemetryArray telemetry_array;
|
||||
}ProgramData;
|
||||
|
||||
|
||||
void print_menu(ProgramData *);
|
||||
void print_data(ProgramData *);
|
||||
void get_nchanels(ProgramData *);
|
||||
void get_chanels(ProgramData *);
|
||||
|
||||
void get_telemetry_file(ProgramData *);
|
||||
TelemetryFile* telemetry_file_create(size_t fs);
|
||||
void telemetry_file_free(ProgramData *);
|
||||
|
||||
void get_telemetry_data(ProgramData *);
|
||||
bool telemetry_array_is_full(ProgramData *);
|
||||
void telemetry_array_alloc(ProgramData *);
|
||||
void telemetry_array_free(ProgramData *);
|
||||
void telemetry_array_set(ProgramData *, uint8_t data);
|
||||
|
||||
void free_data(ProgramData*);
|
||||
void pause(void);
|
||||
|
||||
|
||||
int main(void){
|
||||
|
||||
ProgramData data = {
|
||||
.n_chanels = 0,
|
||||
.chanels = NULL,
|
||||
.telemetry_file = NULL,
|
||||
.telemetry_array = {
|
||||
.base = {
|
||||
.size = 0,
|
||||
.datos = NULL
|
||||
},
|
||||
.offset = 0
|
||||
}
|
||||
};
|
||||
|
||||
print_menu(&data);
|
||||
|
||||
free_data(&data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_menu(ProgramData* ref_data){
|
||||
|
||||
int option = 0;
|
||||
int exit = 0;
|
||||
|
||||
system("clear");
|
||||
printf("MENU DE OPCIONES\n");
|
||||
printf("\t 1- Cargar canales\n");
|
||||
printf("\t 2- Mostrar Datos\n");
|
||||
printf("\t 3- Crear archivo de telemetría\n");
|
||||
printf("\t 4- Recibir telemetria\n");
|
||||
printf("\t 5- Salir\n");
|
||||
|
||||
scanf("%d", &option);
|
||||
|
||||
switch (option) {
|
||||
case 1:
|
||||
get_nchanels(ref_data);
|
||||
get_chanels(ref_data);
|
||||
break;
|
||||
case 2:
|
||||
print_data(ref_data);
|
||||
break;
|
||||
case 3:
|
||||
get_telemetry_file(ref_data);
|
||||
break;
|
||||
case 4:
|
||||
get_telemetry_data(ref_data);
|
||||
break;
|
||||
case 5:
|
||||
exit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if(!exit){
|
||||
print_menu(ref_data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void get_telemetry_data(ProgramData *ref_data){
|
||||
system("clear");
|
||||
printf("RECEPCION DE TELEMETRIA\n");
|
||||
uint8_t read_data;
|
||||
|
||||
do{
|
||||
printf("\nIngresar valor (0 para terminar):");
|
||||
scanf("%" SCNu8, &read_data);
|
||||
|
||||
//printf("Se ha leido: %" SCNu8 "\n", read_data);
|
||||
|
||||
if(read_data > 0){
|
||||
telemetry_array_set(ref_data, read_data);
|
||||
}
|
||||
|
||||
}while(read_data > 0);
|
||||
}
|
||||
|
||||
bool telemetry_array_is_full(ProgramData *ref_data){
|
||||
|
||||
uint8_t* start_add = ref_data->telemetry_array.base.datos;
|
||||
|
||||
if(start_add == NULL){
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* end_add = start_add + ref_data->telemetry_array.base.size;
|
||||
uint8_t* test_add = start_add + ref_data->telemetry_array.offset;
|
||||
return test_add >= (end_add);
|
||||
}
|
||||
|
||||
void telemetry_array_alloc(ProgramData *ref_data){
|
||||
//Si esta vacio reserva espacio para uno.
|
||||
if(ref_data->telemetry_array.base.datos == NULL){
|
||||
ref_data->telemetry_array.base.datos = malloc(sizeof(uint8_t));
|
||||
if(ref_data->telemetry_array.base.datos == NULL){
|
||||
perror("Error asignando memoria para streaming de telemetria.");
|
||||
exit(1);
|
||||
}
|
||||
ref_data->telemetry_array.base.size = 1;
|
||||
ref_data->telemetry_array.offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* result = realloc(ref_data->telemetry_array.base.datos, ref_data->telemetry_array.base.size * 2);
|
||||
|
||||
if(result == NULL){
|
||||
perror("Error reasignando memoria para streaming de telemetria.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ref_data->telemetry_array.base.datos = result;
|
||||
ref_data->telemetry_array.base.size *= 2;
|
||||
|
||||
printf("La nueva capacidad es: %zu \n", ref_data->telemetry_array.base.size);
|
||||
}
|
||||
|
||||
void telemetry_array_free(ProgramData *ref_data){
|
||||
if(ref_data->telemetry_array.base.datos == NULL){
|
||||
free(ref_data->telemetry_array.base.datos);
|
||||
ref_data->telemetry_array.base.datos = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void telemetry_array_set(ProgramData *ref_data, uint8_t data){
|
||||
if(telemetry_array_is_full(ref_data)){
|
||||
printf("Esta lleno, vamos a agrandar \n");
|
||||
telemetry_array_alloc(ref_data);
|
||||
}
|
||||
|
||||
*(ref_data->telemetry_array.base.datos + ref_data->telemetry_array.offset) = data;
|
||||
ref_data->telemetry_array.offset += 1;
|
||||
}
|
||||
|
||||
|
||||
void get_telemetry_file(ProgramData *ref_data){
|
||||
|
||||
size_t fs;
|
||||
|
||||
system("clear");
|
||||
|
||||
printf("CREAR ARCHIVO DE TELEMETRIA\n");
|
||||
printf("\tEnter de size in bytes:");
|
||||
scanf("%zu", &fs);
|
||||
|
||||
telemetry_file_free(ref_data);
|
||||
ref_data->telemetry_file = telemetry_file_create(fs);
|
||||
|
||||
}
|
||||
|
||||
void telemetry_file_free(ProgramData *ref_data){
|
||||
if(ref_data->telemetry_file != NULL){
|
||||
if(ref_data->telemetry_file->datos != NULL){
|
||||
free(ref_data->telemetry_file->datos);
|
||||
ref_data->telemetry_file->datos = NULL;
|
||||
}
|
||||
free(ref_data->telemetry_file);
|
||||
ref_data->telemetry_file = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TelemetryFile* telemetry_file_create(size_t fs){
|
||||
TelemetryFile* telemetry_file = malloc(sizeof(TelemetryFile));
|
||||
|
||||
if(telemetry_file == NULL){
|
||||
perror("Error creating telemetry file.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
telemetry_file->size = fs;
|
||||
telemetry_file->datos = malloc(sizeof(uint8_t)*fs);
|
||||
|
||||
if(telemetry_file->datos == NULL){
|
||||
free(telemetry_file);
|
||||
telemetry_file = NULL;
|
||||
perror("Error allocating memory for the buffer to telemetry file.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return telemetry_file;
|
||||
|
||||
}
|
||||
|
||||
void get_nchanels(ProgramData* ref_data){
|
||||
system("clear");
|
||||
int n_chanels = 0;
|
||||
printf("Cantidad de canales: ");
|
||||
scanf("%d", &n_chanels);
|
||||
|
||||
ref_data->n_chanels = n_chanels;
|
||||
|
||||
}
|
||||
|
||||
void get_chanels(ProgramData* ref_data){
|
||||
if(ref_data->chanels != NULL){
|
||||
free(ref_data->chanels);
|
||||
ref_data->chanels = NULL;
|
||||
}
|
||||
ref_data->chanels = malloc(sizeof(int)*ref_data->n_chanels);
|
||||
if(ref_data->chanels == NULL){
|
||||
perror("No se pudo reservar memoria para los canales.");
|
||||
exit(1);
|
||||
}
|
||||
for(int i=0; i < ref_data->n_chanels; i++){
|
||||
int chanel;
|
||||
printf("Frecuacia en Mhz del canal%d:", i);
|
||||
scanf("%d", &chanel);
|
||||
*(ref_data->chanels + i) = chanel;
|
||||
}
|
||||
}
|
||||
|
||||
void print_data(ProgramData* ref_data){
|
||||
system("clear");
|
||||
printf("DATOS DEL PROGRAMA\n");
|
||||
printf("Cantidad de canales: %d\n", ref_data->n_chanels);
|
||||
|
||||
for (int i=0; i < ref_data->n_chanels; i++){
|
||||
printf("\t CH %d Mhz\n", *(ref_data->chanels + i));
|
||||
}
|
||||
|
||||
if(ref_data->telemetry_file != NULL){
|
||||
printf("Archivo de telemetria creado. Size: %zu bytes.\n", ref_data->telemetry_file->size);
|
||||
}
|
||||
|
||||
printf("Datos de telemetria: ");
|
||||
for(size_t i=0; i < ref_data->telemetry_array.offset; i++){
|
||||
printf("%" SCNu8 ", ", *(ref_data->telemetry_array.base.datos + i));
|
||||
}
|
||||
if(ref_data->telemetry_array.base.size == 0){
|
||||
printf("No hay datos.");
|
||||
}
|
||||
printf("\n");
|
||||
pause();
|
||||
}
|
||||
|
||||
void free_data(ProgramData* ref_data){
|
||||
if(ref_data->chanels){
|
||||
free(ref_data->chanels);
|
||||
}
|
||||
telemetry_file_free(ref_data);
|
||||
telemetry_array_free(ref_data);
|
||||
}
|
||||
|
||||
void pause(void){
|
||||
// 1. Limpiamos el búfer por si quedó algún caracter pendiente del scanf anterior
|
||||
int c;
|
||||
while ((c = getchar()) != '\n' && c != EOF);
|
||||
// 2. Mostramos el mensaje y esperamos a que el usuario presione Enter de verdad
|
||||
printf("Presione Enter para continuar...\n");
|
||||
getchar();
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,28 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void swap(char **, char**);
|
||||
void swap_int(int *, int *);
|
||||
|
||||
int main(void){
|
||||
char *s1 = "Hola";
|
||||
char *s2 = "Mundo";
|
||||
int n1 = 10;
|
||||
int n2 = 20;
|
||||
swap(&s1, &s2);
|
||||
swap_int(&n1, &n2);
|
||||
printf("s1: %s s2: %s\n", s1, s2);
|
||||
printf("n1: %d n2: %d\n", n1, n2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void swap(char **s1, char **s2){
|
||||
char *aux = *s1;
|
||||
*s1 = *s2;
|
||||
*s2 = aux;
|
||||
}
|
||||
|
||||
void swap_int(int* n1, int* n2){
|
||||
int aux = *n1;
|
||||
*n1 = *n2;
|
||||
*n2 = aux;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,48 @@
|
||||
/* ============================================================================
|
||||
* Ejercicio: Modificación de un Puntero a través de un Puntero a Puntero (int **)
|
||||
* ============================================================================
|
||||
* Objetivo:
|
||||
* Comprender el uso de punteros a punteros para modificar la dirección a la
|
||||
* que apunta un puntero original dentro de una función (pasaje por referencia).
|
||||
*
|
||||
* Descripción:
|
||||
* Escribe un programa en C que cumpla con los siguientes requisitos:
|
||||
*
|
||||
* 1. Define dos variables enteras, por ejemplo: `int x = 10;` e `int y = 20;`.
|
||||
* 2. Declara un puntero simple a entero, por ejemplo: `int *ptr = &x;`.
|
||||
* 3. Crea una función llamada `cambiar_puntero` que reciba un puntero a puntero
|
||||
* (`int **p_ref`) y la dirección de otra variable entera (`int *nueva_dir`).
|
||||
* La función debe actualizar el puntero original para que ahora apunte a
|
||||
* esa nueva dirección (`*p_ref = nueva_dir;`).
|
||||
* 4. En la función `main`, imprime el valor al que apunta `ptr` antes de llamar
|
||||
* a la función.
|
||||
* 5. Llama a `cambiar_puntero` pasando la dirección de `ptr` (`&ptr`) y la
|
||||
* dirección de `y` (`&y`).
|
||||
* 6. Vuelve a imprimir el valor al que apunta `ptr` después de la llamada para
|
||||
* verificar que ahora apunta a `y` (su valor debe ser 20).
|
||||
*
|
||||
* Restricciones:
|
||||
* - Debes utilizar obligatoriamente el operador de indirección doble (**).
|
||||
* - No olvides validar los conceptos de memoria y desreferenciación.
|
||||
* ============================================================================ */
|
||||
#include <stdio.h>
|
||||
|
||||
void cambiar_puntero(int**, int*);
|
||||
|
||||
int main(void){
|
||||
|
||||
int x = 20, y = 30;
|
||||
int* ptr = &x;
|
||||
|
||||
printf("contenido de ptr = %d \n", *ptr);
|
||||
|
||||
cambiar_puntero(&ptr, &y);
|
||||
|
||||
|
||||
printf("contenido de ptr = %d\n", *ptr);
|
||||
|
||||
}
|
||||
|
||||
void cambiar_puntero(int** ptr, int *address){
|
||||
*ptr = address;
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user