modelar datos del mundo real agrupando valores.
Incluye 4 ejercicios con pistas y solución y un quiz de 5 preguntas. Tiempo estimado: 80 minutos.
1. struct: agrupar campos
struct Alumno {
char nombre[32];
int edad;
double nota;
};
struct Alumno a = {"Ana", 20, 9.5};
a.edad++; // acceso con el punto
printf("%s %d\n", a.nombre, a.edad);
- Se pasa por valor (copia entera) como cualquier variable. Para estructuras grandes pasa un puntero:
void f(const struct Alumno *a). - Con puntero se accede con la flecha:
p->edad≡(*p).edad. - Puedes tener arrays de structs:
struct Alumno clase[30]; clase[2].nota = 7; - Y structs dentro de structs, y punteros dentro de structs.
2. typedef: ponerle nombre al tipo
typedef struct {
double x, y;
} Punto;
Punto p = {1.5, 2.0};
Para estructuras que se refieren a sí mismas (listas, árboles) hay que dar nombre al struct:
typedef struct Nodo {
int dato;
struct Nodo *sig; // aquí aún no existe el alias "Nodo"
} Nodo;
3. Inicialización cómoda (C99)
Punto p = { .y = 3.0, .x = 1.0 }; // por nombre de campo
Punto q = { 0 }; // todo a cero
4. enum: constantes con nombre
enum Dia { LUN, MAR, MIE, JUE, VIE, SAB, DOM }; // LUN=0, MAR=1...
enum Dia hoy = MIE;
switch (hoy) { case SAB: case DOM: puts("finde"); break; default: puts("curro"); }
Puedes fijar valores: enum { OK = 0, ERR_ARCHIVO = 10, ERR_RED } (ERR_RED vale 11).
Mucho más legible que "números mágicos".
5. union (breve)
Todos los campos comparten el mismo espacio de memoria; solo uno es válido a la vez. Se usa con una etiqueta que indica cuál:
typedef struct {
enum { ENTERO, REAL } tipo;
union { int i; double d; } v;
} Numero;
6. Tamaño y alineación
sizeof(struct) puede ser mayor que la suma de los campos: el compilador añade padding para alinear. Nunca asumas el tamaño; usa sizeof.
7. Ordenar con qsort
qsort está en <stdlib.h> y ordena cualquier array si le dices cómo comparar dos elementos:
int comparar(const void *pa, const void *pb) {
const Alumno *a = pa, *b = pb; // convierte void* al tipo real
if (a->nota > b->nota) return -1; // a antes que b
if (a->nota < b->nota) return 1;
return strcmp(a->nombre, b->nombre);
}
qsort(clase, n, sizeof clase[0], comparar);
Esto es pasar una función como parámetro (un puntero a función). Convención: devuelve <0 si a va antes, 0 si empatan, >0 si va después. (Nunca devuelvas a - b en enteros grandes: puede desbordar.)
Prueba esto
- Define
struct Fecha {int d, m, a;}y una función que diga si una fecha es anterior a otra. - Un array de 5
Puntoy busca el más lejano al origen. - Haz un
enum Color {ROJO, VERDE, AZUL}y una funciónconst char *nombre_color(enum Color).
Ejercicios prácticos del módulo 9
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.
9.1 Distancia entre puntos
Entrada de ejemplo
0 0 3 4
Salida esperada
distancia=5.000
Tu punto de partida
#include <stdio.h>
#include <math.h>
typedef struct {
double x, y;
} Punto;
double distancia(Punto a, Punto b) {
// TODO
return 0;
}
int main(void) {
Punto p, q;
scanf("%lf %lf %lf %lf", &p.x, &p.y, &q.x, &q.y);
printf("distancia=%.3f\n", distancia(p, q));
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
Se accede a los campos con el punto: a.x, a.y.
Pista 2
distancia = sqrt(dx*dx + dy*dy).
Ver solución (inténtalo antes)
#include <stdio.h>
#include <math.h>
typedef struct {
double x, y;
} Punto;
double distancia(Punto a, Punto b) {
double dx = a.x - b.x, dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
int main(void) {
Punto p, q;
scanf("%lf %lf %lf %lf", &p.x, &p.y, &q.x, &q.y);
printf("distancia=%.3f\n", distancia(p, q));
return 0;
}9.2 Lista de alumnos
Entrada de ejemplo
3 Ana 9.5 Luis 6 Mar 7.5
Salida esperada
mejor=Ana (9.50) media=7.67
Tu punto de partida
#include <stdio.h>
struct Alumno {
char nombre[32];
double nota;
};
int main(void) {
struct Alumno a[50];
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
// TODO: lee nombre (%31s) y nota (%lf) en a[i]
}
// TODO: busca el mejor, calcula la media e imprime
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
Un array de structs: a[i].nombre y a[i].nota.
Pista 2
Para el nombre (array de char) no hace falta &; para la nota (double) si.
Pista 3
Guarda el INDICE del mejor, no solo la nota: asi tienes tambien el nombre.
Ver solución (inténtalo antes)
#include <stdio.h>
struct Alumno {
char nombre[32];
double nota;
};
int main(void) {
struct Alumno a[50];
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%31s %lf", a[i].nombre, &a[i].nota);
int mejor = 0;
double suma = 0;
for (int i = 0; i < n; i++) {
if (a[i].nota > a[mejor].nota) mejor = i;
suma += a[i].nota;
}
printf("mejor=%s (%.2f) media=%.2f\n", a[mejor].nombre, a[mejor].nota, suma / n);
return 0;
}9.3 Ordenar con qsort
Entrada de ejemplo
4 Luis 6 Ana 9.5 Mar 6 Eva 7
Salida esperada
Ana 9.50 Eva 7.00 Luis 6.00 Mar 6.00
Tu punto de partida
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char nombre[32];
double nota;
} Alumno;
int comparar(const void *pa, const void *pb) {
const Alumno *a = pa, *b = pb;
// TODO: devuelve <0 si a va antes que b, >0 si va despues, 0 si empatan
return 0;
}
int main(void) {
Alumno v[50];
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%31s %lf", v[i].nombre, &v[i].nota);
qsort(v, n, sizeof v[0], comparar);
for (int i = 0; i < n; i++) printf("%s %.2f\n", v[i].nombre, v[i].nota);
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
Con un puntero a struct se usa la flecha: a->nota (equivale a (*a).nota).
Pista 2
Para orden descendente, devuelve -1 cuando a->nota es MAYOR que b->nota.
Pista 3
Para el desempate, strcmp(a->nombre, b->nombre) ya devuelve <0, 0 o >0.
Ver solución (inténtalo antes)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char nombre[32];
double nota;
} Alumno;
int comparar(const void *pa, const void *pb) {
const Alumno *a = pa, *b = pb;
if (a->nota > b->nota) return -1;
if (a->nota < b->nota) return 1;
return strcmp(a->nombre, b->nombre);
}
int main(void) {
Alumno v[50];
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) scanf("%31s %lf", v[i].nombre, &v[i].nota);
qsort(v, n, sizeof v[0], comparar);
for (int i = 0; i < n; i++) printf("%s %.2f\n", v[i].nombre, v[i].nota);
return 0;
}9.4 Semaforo con enum
Entrada de ejemplo
4
Salida esperada
VERDE AMARILLO ROJO VERDE
Tu punto de partida
#include <stdio.h>
enum Estado { VERDE, AMARILLO, ROJO };
enum Estado siguiente(enum Estado e) {
// TODO
return e;
}
const char *nombre(enum Estado e) {
// TODO
return "?";
}
int main(void) {
int n;
scanf("%d", &n);
enum Estado e = ROJO;
for (int i = 0; i < n; i++) {
e = siguiente(e);
printf("%s\n", nombre(e));
}
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
En un switch sobre un enum puedes devolver directamente en cada case; no hace falta break despues de return.
Pista 2
Devolver un literal de cadena desde una funcion es seguro: vive durante todo el programa.
Ver solución (inténtalo antes)
#include <stdio.h>
enum Estado { VERDE, AMARILLO, ROJO };
enum Estado siguiente(enum Estado e) {
switch (e) {
case VERDE: return AMARILLO;
case AMARILLO: return ROJO;
default: return VERDE;
}
}
const char *nombre(enum Estado e) {
switch (e) {
case VERDE: return "VERDE";
case AMARILLO: return "AMARILLO";
default: return "ROJO";
}
}
int main(void) {
int n;
scanf("%d", &n);
enum Estado e = ROJO;
for (int i = 0; i < n; i++) {
e = siguiente(e);
printf("%s\n", nombre(e));
}
return 0;
}Quiz del módulo 9
5 preguntas para comprobar que has fijado los conceptos. Las opciones se barajan cada vez.