juntar todo lo aprendido en un programa real.
Incluye 4 ejercicios con pistas y solución y un quiz de 5 preguntas. Tiempo estimado: 120 minutos.
1. Estructuras de datos básicas
Programar bien es, en gran parte, elegir cómo guardar los datos.
| Estructura | Acceso | Insertar/borrar | Cuándo |
|---|---|---|---|
| Array / array dinámico | v[i] O(1) |
al final O(1) amortizado; en medio O(n) | por defecto: lo más simple y rápido |
| Lista enlazada | O(n) | O(1) si ya tienes el nodo | inserciones/borrados frecuentes en medio |
| Pila (LIFO) | solo el tope | push/pop O(1) | deshacer, recorrer, evaluar expresiones |
| Cola (FIFO) | frente | encolar/desencolar O(1) | turnos, buffers |
Lista enlazada
typedef struct Nodo {
int dato;
struct Nodo *sig; // NULL en el último
} Nodo;
cabeza ──▶ [1|•]──▶ [2|•]──▶ [3|NULL]
Reglas de supervivencia:
1. Dibuja los nodos y flechas en papel antes de escribir.
2. Cuando cambies un enlace, guarda antes el que vas a perder (Nodo *sig = p->sig;).
3. Siempre trata el caso lista vacía (cabeza == NULL).
4. Para liberar: guarda sig, luego free(p).
Invertir una lista: tres punteros (prev, actual, sig) y un bucle que va girando cada flecha.
Pila como TAD
Una pila solo expone push, pop, vacia. Por dentro puede ser un array dinámico o una lista; quien la usa no lo sabe ni le importa (encapsulación). Se usa para validar paréntesis, evaluar expresiones, deshacer acciones...
2. Cómo atacar un proyecto
- Entiende el problema: entradas, salidas, casos raros (vacío, duplicados, errores).
- Diseña los datos primero: structs y qué funciones los manejan.
- Escribe funciones pequeñas y pruébalas de una en una (empieza por
buscar). - Prueba antes de seguir: un programa de 100 líneas que falla es mucho más difícil de depurar que 5 trozos de 20 comprobados.
- Maneja errores: malloc→NULL, fopen→NULL, entrada inválida.
- Libera todo; comprueba con
-fsanitize=address.
3. El proyecto: agenda de contactos (12.3 y 12.4)
Un intérprete de comandos con memoria dinámica y persistencia:
add ana 111 -> ok
add ana 999 -> duplicado
find ana -> ana: 111
list -> (todos, por orden alfabético)
guardar a.txt -> guardados 1
cargar a.txt -> cargados 1
Usa: struct, array dinámico con realloc (cap 4, ×2), strcmp, memmove, qsort, ficheros de texto con ; como separador, y funciones pequeñas con una única responsabilidad.
4. Siguientes pasos (después del curso)
Con la base de C que tienes, puedes ir en varias direcciones:
- Estructuras avanzadas: tablas hash, árboles binarios de búsqueda, grafos.
- Sistema: procesos, señales, sockets (programación de red), hilos (pthreads).
- Embebido: Arduino/ESP32, STM32 (C puro sobre hardware).
- Juegos/gráficos: SDL2 o raylib (muy amigable para C).
- Lectura: The C Programming Language (Kernighan & Ritchie), C Programming: A Modern Approach (K. N. King), y el sitio https://en.cppreference.com/w/c
Retos propuestos para consolidar
- Tres en raya en consola (matriz 3×3 y comprobación de ganador).
- Gestor de tareas (el proyecto de la agenda, pero con prioridades y fechas).
- Calculadora de expresiones (
3 + 4 * (2 - 1)) usando dos pilas. - Contador de frecuencia de palabras de un fichero con una tabla hash propia.
- Mini intérprete de un lenguaje de 5 instrucciones.
Ejercicios prácticos del módulo 12
Programar se aprende programando: intenta cada ejercicio antes de mirar las pistas, y usa la solución solo para comparar. Marca los que resuelvas y tu progreso se guarda en este navegador.
12.1 Lista enlazada
Entrada de ejemplo
1 2 3 0
Salida esperada
1 2 3 3 2 1
Tu punto de partida
#include <stdio.h>
#include <stdlib.h>
typedef struct Nodo {
int dato;
struct Nodo *sig;
} Nodo;
/* Anade x al final y devuelve la cabeza de la lista (puede ser el nodo nuevo si estaba vacia). */
Nodo *insertar_final(Nodo *cabeza, int x) {
// TODO
return cabeza;
}
/* Imprime los datos separados por espacio y un salto de linea al final. */
void imprimir(const Nodo *n) {
// TODO
}
/* Invierte los enlaces y devuelve la nueva cabeza. */
Nodo *invertir(Nodo *cabeza) {
// TODO
return cabeza;
}
void liberar(Nodo *cabeza) {
// TODO
}
int main(void) {
Nodo *lista = NULL;
int x;
while (scanf("%d", &x) == 1 && x != 0) lista = insertar_final(lista, x);
imprimir(lista);
lista = invertir(lista);
imprimir(lista);
liberar(lista);
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
Dibuja la lista en papel: cada nodo es una caja con el dato y una flecha al siguiente; el ultimo apunta a NULL.
Pista 2
insertar_final: reserva el nodo, y si hay cabeza recorre con while (p->sig) p = p->sig; para llegar al ultimo.
Pista 3
invertir necesita 3 punteros: prev (empieza NULL), actual y sig (guardado ANTES de cambiar actual->sig).
Pista 4
liberar: guarda p->sig antes de hacer free(p) (despues de liberar ya no puedes leerlo).
Ver solución (inténtalo antes)
#include <stdio.h>
#include <stdlib.h>
typedef struct Nodo {
int dato;
struct Nodo *sig;
} Nodo;
Nodo *insertar_final(Nodo *cabeza, int x) {
Nodo *nuevo = malloc(sizeof *nuevo);
if (!nuevo) return cabeza;
nuevo->dato = x;
nuevo->sig = NULL;
if (!cabeza) return nuevo;
Nodo *p = cabeza;
while (p->sig) p = p->sig;
p->sig = nuevo;
return cabeza;
}
void imprimir(const Nodo *n) {
for (; n; n = n->sig) printf("%d%s", n->dato, n->sig ? " " : "");
printf("\n");
}
Nodo *invertir(Nodo *cabeza) {
Nodo *prev = NULL;
while (cabeza) {
Nodo *sig = cabeza->sig;
cabeza->sig = prev;
prev = cabeza;
cabeza = sig;
}
return prev;
}
void liberar(Nodo *cabeza) {
while (cabeza) {
Nodo *sig = cabeza->sig;
free(cabeza);
cabeza = sig;
}
}
int main(void) {
Nodo *lista = NULL;
int x;
while (scanf("%d", &x) == 1 && x != 0) lista = insertar_final(lista, x);
imprimir(lista);
lista = invertir(lista);
imprimir(lista);
liberar(lista);
return 0;
}12.2 Pila (TAD) y parentesis balanceados
Entrada de ejemplo
(a[b]{c})
Salida esperada
balanceado
Tu punto de partida
pila.h
#ifndef PILA_H
#define PILA_H
/* Pila de caracteres. El struct es OPACO: los usuarios no ven su interior. */
typedef struct Pila Pila;
Pila *pila_crear(void);
void pila_destruir(Pila *p);
int pila_vacia(const Pila *p);
void pila_push(Pila *p, char c);
char pila_pop(Pila *p); /* precondicion: la pila no esta vacia */
#endifpila.c
#include <stdlib.h>
#include "pila.h"
struct Pila {
char *datos;
int n;
int cap;
};
Pila *pila_crear(void) {
// TODO: reserva el struct (y el array con capacidad inicial, p.ej. 8)
return NULL;
}
void pila_destruir(Pila *p) {
// TODO: libera el array y el struct
}
int pila_vacia(const Pila *p) {
// TODO
return 1;
}
void pila_push(Pila *p, char c) {
// TODO: si n == cap, duplica con realloc
}
char pila_pop(Pila *p) {
// TODO
return 0;
}main.c
#include <stdio.h>
#include "pila.h"
static char abre_de(char c) {
switch (c) {
case ')': return '(';
case ']': return '[';
case '}': return '{';
}
return 0;
}
int main(void) {
char s[256];
while (fgets(s, sizeof s, stdin)) {
Pila *p = pila_crear();
int ok = 1;
for (int i = 0; s[i] && ok; i++) {
char c = s[i];
if (c == '(' || c == '[' || c == '{')
pila_push(p, c);
else if (abre_de(c)) {
if (pila_vacia(p) || pila_pop(p) != abre_de(c)) ok = 0;
}
}
if (!pila_vacia(p)) ok = 0;
printf("%s\n", ok ? "balanceado" : "no balanceado");
pila_destruir(p);
}
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
El 'tope' es la posicion n-1: push guarda en datos[n] y hace n++; pop hace --n y devuelve datos[n].
Pista 2
pila_crear necesita DOS reservas: el struct y el array. Libera ambos en pila_destruir (primero el array).
Pista 3
Crecimiento: if (p->n == p->cap) { cap *= 2; datos = realloc(datos, cap); }
Ver solución (inténtalo antes)
pila.c
#include <stdlib.h>
#include "pila.h"
struct Pila {
char *datos;
int n;
int cap;
};
Pila *pila_crear(void) {
Pila *p = malloc(sizeof *p);
if (!p) return NULL;
p->cap = 8;
p->n = 0;
p->datos = malloc(p->cap);
if (!p->datos) { free(p); return NULL; }
return p;
}
void pila_destruir(Pila *p) {
if (!p) return;
free(p->datos);
free(p);
}
int pila_vacia(const Pila *p) {
return p->n == 0;
}
void pila_push(Pila *p, char c) {
if (p->n == p->cap) {
int ncap = p->cap * 2;
char *tmp = realloc(p->datos, ncap);
if (!tmp) return;
p->datos = tmp;
p->cap = ncap;
}
p->datos[p->n++] = c;
}
char pila_pop(Pila *p) {
return p->datos[--p->n];
}12.3 PROYECTO: agenda de contactos (en memoria)
Entrada de ejemplo
add ana 111 add luis 222 add ana 333 find ana find pepe list del luis count del luis quit
Salida esperada
ok ok duplicado ana: 111 no existe ana: 111 luis: 222 ok 1 no existe
Tu punto de partida
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char nombre[32];
char tel[16];
} Contacto;
typedef struct {
Contacto *v; /* array dinamico */
int n; /* usados */
int cap; /* reservados */
} Agenda;
static int cmp_contacto(const void *a, const void *b) {
return strcmp(((const Contacto *)a)->nombre, ((const Contacto *)b)->nombre);
}
/* Devuelve un puntero al contacto con ese nombre, o NULL si no existe. */
Contacto *agenda_buscar(const Agenda *a, const char *nombre) {
// TODO
return NULL;
}
/* Anade un contacto. Devuelve 1 si lo anade, 0 si ya existia ese nombre. Crece con realloc. */
int agenda_agregar(Agenda *a, const char *nombre, const char *tel) {
// TODO
return 0;
}
/* Borra el contacto. Devuelve 1 si existia, 0 si no. (pista: memmove para tapar el hueco) */
int agenda_borrar(Agenda *a, const char *nombre) {
// TODO
return 0;
}
/* Imprime "nombre: tel" por orden alfabetico (usa qsort sobre una COPIA con cmp_contacto). */
void agenda_listar(const Agenda *a) {
// TODO
}
void agenda_liberar(Agenda *a) {
// TODO
}
int main(void) {
Agenda ag = {NULL, 0, 0};
char cmd[16], nombre[32], tel[16];
while (scanf("%15s", cmd) == 1) {
if (strcmp(cmd, "add") == 0) {
scanf("%31s %15s", nombre, tel);
printf("%s\n", agenda_agregar(&ag, nombre, tel) ? "ok" : "duplicado");
} else if (strcmp(cmd, "find") == 0) {
scanf("%31s", nombre);
Contacto *c = agenda_buscar(&ag, nombre);
if (c) printf("%s: %s\n", c->nombre, c->tel);
else printf("no existe\n");
} else if (strcmp(cmd, "del") == 0) {
scanf("%31s", nombre);
printf("%s\n", agenda_borrar(&ag, nombre) ? "ok" : "no existe");
} else if (strcmp(cmd, "list") == 0) {
agenda_listar(&ag);
} else if (strcmp(cmd, "count") == 0) {
printf("%d\n", ag.n);
} else if (strcmp(cmd, "quit") == 0) {
break;
}
}
agenda_liberar(&ag);
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
Empieza por agenda_buscar (recorrido lineal con strcmp): casi todo lo demas la usa.
Pista 2
agenda_agregar: si n == cap crece (cap ? cap*2 : 4) con realloc en un puntero temporal. Copia las cadenas con snprintf o strncpy.
Pista 3
agenda_borrar: calcula el indice con aritmetica de punteros (c - a->v), y tapa el hueco con memmove(&v[i], &v[i+1], (n-i-1)*sizeof v[0]).
Pista 4
agenda_listar: copia el array (malloc+memcpy), ordena la copia con qsort y libera la copia al acabar.
Ver solución (inténtalo antes)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char nombre[32];
char tel[16];
} Contacto;
typedef struct {
Contacto *v; /* array dinamico */
int n; /* usados */
int cap; /* reservados */
} Agenda;
static int cmp_contacto(const void *a, const void *b) {
return strcmp(((const Contacto *)a)->nombre, ((const Contacto *)b)->nombre);
}
Contacto *agenda_buscar(const Agenda *a, const char *nombre) {
for (int i = 0; i < a->n; i++)
if (strcmp(a->v[i].nombre, nombre) == 0) return &a->v[i];
return NULL;
}
int agenda_agregar(Agenda *a, const char *nombre, const char *tel) {
if (agenda_buscar(a, nombre)) return 0;
if (a->n == a->cap) {
int ncap = a->cap ? a->cap * 2 : 4;
Contacto *tmp = realloc(a->v, ncap * sizeof *tmp);
if (!tmp) return 0;
a->v = tmp;
a->cap = ncap;
}
snprintf(a->v[a->n].nombre, sizeof a->v[a->n].nombre, "%s", nombre);
snprintf(a->v[a->n].tel, sizeof a->v[a->n].tel, "%s", tel);
a->n++;
return 1;
}
int agenda_borrar(Agenda *a, const char *nombre) {
Contacto *c = agenda_buscar(a, nombre);
if (!c) return 0;
int i = (int)(c - a->v);
memmove(&a->v[i], &a->v[i + 1], (a->n - i - 1) * sizeof a->v[0]);
a->n--;
return 1;
}
void agenda_listar(const Agenda *a) {
if (a->n == 0) return;
Contacto *copia = malloc(a->n * sizeof *copia);
if (!copia) return;
memcpy(copia, a->v, a->n * sizeof *copia);
qsort(copia, a->n, sizeof *copia, cmp_contacto);
for (int i = 0; i < a->n; i++) printf("%s: %s\n", copia[i].nombre, copia[i].tel);
free(copia);
}
void agenda_liberar(Agenda *a) {
free(a->v);
a->v = NULL;
a->n = a->cap = 0;
}
int main(void) {
Agenda ag = {NULL, 0, 0};
char cmd[16], nombre[32], tel[16];
while (scanf("%15s", cmd) == 1) {
if (strcmp(cmd, "add") == 0) {
scanf("%31s %15s", nombre, tel);
printf("%s\n", agenda_agregar(&ag, nombre, tel) ? "ok" : "duplicado");
} else if (strcmp(cmd, "find") == 0) {
scanf("%31s", nombre);
Contacto *c = agenda_buscar(&ag, nombre);
if (c) printf("%s: %s\n", c->nombre, c->tel);
else printf("no existe\n");
} else if (strcmp(cmd, "del") == 0) {
scanf("%31s", nombre);
printf("%s\n", agenda_borrar(&ag, nombre) ? "ok" : "no existe");
} else if (strcmp(cmd, "list") == 0) {
agenda_listar(&ag);
} else if (strcmp(cmd, "count") == 0) {
printf("%d\n", ag.n);
} else if (strcmp(cmd, "quit") == 0) {
break;
}
}
agenda_liberar(&ag);
return 0;
}12.4 PROYECTO: guardar y cargar la agenda
Entrada de ejemplo
add ana 111 add luis 222 guardar a.txt del ana cargar a.txt list quit
Salida esperada
ok ok guardados 2 ok cargados 2 ana: 111 luis: 222
Tu punto de partida
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char nombre[32];
char tel[16];
} Contacto;
typedef struct {
Contacto *v; /* array dinamico */
int n; /* usados */
int cap; /* reservados */
} Agenda;
static int cmp_contacto(const void *a, const void *b) {
return strcmp(((const Contacto *)a)->nombre, ((const Contacto *)b)->nombre);
}
Contacto *agenda_buscar(const Agenda *a, const char *nombre) {
for (int i = 0; i < a->n; i++)
if (strcmp(a->v[i].nombre, nombre) == 0) return &a->v[i];
return NULL;
}
int agenda_agregar(Agenda *a, const char *nombre, const char *tel) {
if (agenda_buscar(a, nombre)) return 0;
if (a->n == a->cap) {
int ncap = a->cap ? a->cap * 2 : 4;
Contacto *tmp = realloc(a->v, ncap * sizeof *tmp);
if (!tmp) return 0;
a->v = tmp;
a->cap = ncap;
}
snprintf(a->v[a->n].nombre, sizeof a->v[a->n].nombre, "%s", nombre);
snprintf(a->v[a->n].tel, sizeof a->v[a->n].tel, "%s", tel);
a->n++;
return 1;
}
int agenda_borrar(Agenda *a, const char *nombre) {
Contacto *c = agenda_buscar(a, nombre);
if (!c) return 0;
int i = (int)(c - a->v);
memmove(&a->v[i], &a->v[i + 1], (a->n - i - 1) * sizeof a->v[0]);
a->n--;
return 1;
}
void agenda_listar(const Agenda *a) {
if (a->n == 0) return;
Contacto *copia = malloc(a->n * sizeof *copia);
if (!copia) return;
memcpy(copia, a->v, a->n * sizeof *copia);
qsort(copia, a->n, sizeof *copia, cmp_contacto);
for (int i = 0; i < a->n; i++) printf("%s: %s\n", copia[i].nombre, copia[i].tel);
free(copia);
}
void agenda_liberar(Agenda *a) {
free(a->v);
a->v = NULL;
a->n = a->cap = 0;
}
/* Guarda la agenda en un fichero de texto, una linea "nombre;tel" por contacto.
Devuelve cuantos contactos guardo, o -1 si no pudo abrir el fichero. */
int agenda_guardar(const Agenda *a, const char *fichero) {
// TODO
return -1;
}
/* Vacia la agenda y carga el fichero. Devuelve cuantos cargo, o -1 si no existe. */
int agenda_cargar(Agenda *a, const char *fichero) {
// TODO (reutiliza agenda_agregar)
return -1;
}
int main(void) {
Agenda ag = {NULL, 0, 0};
char cmd[16], nombre[32], tel[16];
char fichero[64];
while (scanf("%15s", cmd) == 1) {
if (strcmp(cmd, "add") == 0) {
scanf("%31s %15s", nombre, tel);
printf("%s\n", agenda_agregar(&ag, nombre, tel) ? "ok" : "duplicado");
} else if (strcmp(cmd, "find") == 0) {
scanf("%31s", nombre);
Contacto *c = agenda_buscar(&ag, nombre);
if (c) printf("%s: %s\n", c->nombre, c->tel);
else printf("no existe\n");
} else if (strcmp(cmd, "del") == 0) {
scanf("%31s", nombre);
printf("%s\n", agenda_borrar(&ag, nombre) ? "ok" : "no existe");
} else if (strcmp(cmd, "list") == 0) {
agenda_listar(&ag);
} else if (strcmp(cmd, "count") == 0) {
printf("%d\n", ag.n);
} else if (strcmp(cmd, "guardar") == 0) {
scanf("%63s", fichero);
int k = agenda_guardar(&ag, fichero);
if (k < 0) printf("error de fichero\n");
else printf("guardados %d\n", k);
} else if (strcmp(cmd, "cargar") == 0) {
scanf("%63s", fichero);
int k = agenda_cargar(&ag, fichero);
if (k < 0) printf("error de fichero\n");
else printf("cargados %d\n", k);
} else if (strcmp(cmd, "quit") == 0) {
break;
}
}
agenda_liberar(&ag);
return 0;
}Cópialo en tu editor, complétalo, compílalo (gcc -Wall -Wextra programa.c -o programa) y prueba la entrada de ejemplo. Para que se corrija solo con varios casos de prueba, descarga el curso.
Pista 1
guardar: fopen("w"), un fprintf(f, "%s;%s\n", ...) por contacto, fclose. Devuelve a->n.
Pista 2
cargar: fopen("r"); pon a->n = 0 (vaciar) y lee con fscanf(f, " %31[^;];%15s", nombre, tel) == 2 en bucle (el espacio inicial del formato salta el salto de linea anterior).
Pista 3
Por cada registro leido llama a agenda_agregar, que ya sabe crecer el array.
Ver solución (inténtalo antes)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char nombre[32];
char tel[16];
} Contacto;
typedef struct {
Contacto *v; /* array dinamico */
int n; /* usados */
int cap; /* reservados */
} Agenda;
static int cmp_contacto(const void *a, const void *b) {
return strcmp(((const Contacto *)a)->nombre, ((const Contacto *)b)->nombre);
}
Contacto *agenda_buscar(const Agenda *a, const char *nombre) {
for (int i = 0; i < a->n; i++)
if (strcmp(a->v[i].nombre, nombre) == 0) return &a->v[i];
return NULL;
}
int agenda_agregar(Agenda *a, const char *nombre, const char *tel) {
if (agenda_buscar(a, nombre)) return 0;
if (a->n == a->cap) {
int ncap = a->cap ? a->cap * 2 : 4;
Contacto *tmp = realloc(a->v, ncap * sizeof *tmp);
if (!tmp) return 0;
a->v = tmp;
a->cap = ncap;
}
snprintf(a->v[a->n].nombre, sizeof a->v[a->n].nombre, "%s", nombre);
snprintf(a->v[a->n].tel, sizeof a->v[a->n].tel, "%s", tel);
a->n++;
return 1;
}
int agenda_borrar(Agenda *a, const char *nombre) {
Contacto *c = agenda_buscar(a, nombre);
if (!c) return 0;
int i = (int)(c - a->v);
memmove(&a->v[i], &a->v[i + 1], (a->n - i - 1) * sizeof a->v[0]);
a->n--;
return 1;
}
void agenda_listar(const Agenda *a) {
if (a->n == 0) return;
Contacto *copia = malloc(a->n * sizeof *copia);
if (!copia) return;
memcpy(copia, a->v, a->n * sizeof *copia);
qsort(copia, a->n, sizeof *copia, cmp_contacto);
for (int i = 0; i < a->n; i++) printf("%s: %s\n", copia[i].nombre, copia[i].tel);
free(copia);
}
void agenda_liberar(Agenda *a) {
free(a->v);
a->v = NULL;
a->n = a->cap = 0;
}
int agenda_guardar(const Agenda *a, const char *fichero) {
FILE *f = fopen(fichero, "w");
if (!f) return -1;
for (int i = 0; i < a->n; i++) fprintf(f, "%s;%s\n", a->v[i].nombre, a->v[i].tel);
fclose(f);
return a->n;
}
int agenda_cargar(Agenda *a, const char *fichero) {
FILE *f = fopen(fichero, "r");
if (!f) return -1;
a->n = 0;
char nombre[32], tel[16];
int cargados = 0;
while (fscanf(f, " %31[^;];%15s", nombre, tel) == 2)
if (agenda_agregar(a, nombre, tel)) cargados++;
fclose(f);
return cargados;
}
int main(void) {
Agenda ag = {NULL, 0, 0};
char cmd[16], nombre[32], tel[16];
char fichero[64];
while (scanf("%15s", cmd) == 1) {
if (strcmp(cmd, "add") == 0) {
scanf("%31s %15s", nombre, tel);
printf("%s\n", agenda_agregar(&ag, nombre, tel) ? "ok" : "duplicado");
} else if (strcmp(cmd, "find") == 0) {
scanf("%31s", nombre);
Contacto *c = agenda_buscar(&ag, nombre);
if (c) printf("%s: %s\n", c->nombre, c->tel);
else printf("no existe\n");
} else if (strcmp(cmd, "del") == 0) {
scanf("%31s", nombre);
printf("%s\n", agenda_borrar(&ag, nombre) ? "ok" : "no existe");
} else if (strcmp(cmd, "list") == 0) {
agenda_listar(&ag);
} else if (strcmp(cmd, "count") == 0) {
printf("%d\n", ag.n);
} else if (strcmp(cmd, "guardar") == 0) {
scanf("%63s", fichero);
int k = agenda_guardar(&ag, fichero);
if (k < 0) printf("error de fichero\n");
else printf("guardados %d\n", k);
} else if (strcmp(cmd, "cargar") == 0) {
scanf("%63s", fichero);
int k = agenda_cargar(&ag, fichero);
if (k < 0) printf("error de fichero\n");
else printf("cargados %d\n", k);
} else if (strcmp(cmd, "quit") == 0) {
break;
}
}
agenda_liberar(&ag);
return 0;
}Quiz del módulo 12
5 preguntas para comprobar que has fijado los conceptos. Las opciones se barajan cada vez.