Puntero a struct en C: ejercicio resuelto

Puntero a struct en C: ejercicio resuelto

Si buscas puntero a struct en C ejercicio resuelto, aquí tienes la diferencia entre acceso por valor (s.campo) y acceso por puntero (p->campo), junto con la asignación dinámica de structs con malloc.

El operador flecha -> es equivalente a desreferenciar el puntero y acceder al campo: p->campo es azúcar sintáctico para (*p).campo.

Enunciado

Define una struct Producto con campos nombre (cadena de 32 caracteres), precio (double) y stock (int). Crea una función que reciba un puntero a Producto, aplique un descuento porcentual al precio y reduzca el stock en 1. Muestra el resultado tanto con acceso estático como dinámico.

Solución en C

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NOMBRE 32

typedef struct {
    char nombre[MAX_NOMBRE];
    double precio;
    int stock;
} Producto;

/* Modifica el producto apuntado por p */
void aplicar_descuento(Producto *p, double pct) {
    p->precio *= (1.0 - pct / 100.0);
    p->stock--;
}

void imprimir(const Producto *p) {
    printf("%-20s  precio=%.2f  stock=%d\n", p->nombre, p->precio, p->stock);
}

int main(void) {
    /* --- Acceso estático --- */
    Producto a;
    strncpy(a.nombre, "Teclado mecánico", MAX_NOMBRE - 1);
    a.nombre[MAX_NOMBRE - 1] = '\0';
    a.precio = 89.99;
    a.stock  = 10;

    printf("Antes:  "); imprimir(&a);
    aplicar_descuento(&a, 15.0);   /* 15 % de descuento */
    printf("Después: "); imprimir(&a);

    printf("\n");

    /* --- Asignación dinámica --- */
    Producto *b = malloc(sizeof(Producto));
    if (!b) { perror("malloc"); return 1; }
    strncpy(b->nombre, "Ratón inalámbrico", MAX_NOMBRE - 1);
    b->nombre[MAX_NOMBRE - 1] = '\0';
    b->precio = 34.50;
    b->stock  = 5;

    printf("Antes:  "); imprimir(b);
    aplicar_descuento(b, 10.0);    /* 10 % de descuento */
    printf("Después: "); imprimir(b);

    free(b);
    return 0;
}

Resultado esperado

1
2
3
4
5
Antes:  Teclado mecánico      precio=89.99  stock=10
Después: Teclado mecánico      precio=76.49  stock=9

Antes:  Ratón inalámbrico     precio=34.50  stock=5
Después: Ratón inalámbrico     precio=31.05  stock=4

Errores frecuentes

  • Usar . en lugar de -> con un puntero: p.precio con un Producto * es un error de compilación; se necesita p->precio.
  • No inicializar todos los campos antes de imprimir: malloc no inicializa la memoria; los campos pueden tener valores basura.
  • No comprobar el resultado de malloc: si devuelve NULL y se accede al puntero, el programa termina con fallo de segmento.
  • Olvidar free(b) al final: cada malloc debe tener su free correspondiente para evitar fugas de memoria.

Aplicación práctica

Los punteros a structs son el patrón central de la programación en C con datos complejos: listas enlazadas, árboles, tablas hash y módulos de software que pasan estructuras grandes entre funciones sin copiarlas. Pasar const Producto * es más eficiente que pasar Producto por valor cuando la struct es grande.

Siguiente ejercicio recomendado

Práctica guiada y libro completo

Si quieres una ruta completa con progresión real de dificultad:

FAQ

¿Cuándo usar struct por valor y cuándo por puntero?

Usa por valor cuando la struct es pequeña (1–2 campos numéricos) y no necesitas modificarla en la función llamada. Usa por puntero cuando la struct es grande (evita copiar), cuando necesitas modificar sus campos en la función o cuando se trata de nodos de una estructura dinámica (lista, árbol).

¿Qué diferencia hay entre malloc(sizeof(Producto)) y declarar Producto b?

Producto b asigna la struct en la pila (stack), que se libera automáticamente al salir del bloque. malloc asigna en el montón (heap), con vida independiente del bloque donde se creó, pero requiere free explícito. El heap es adecuado cuando la vida de la struct debe superar a la función que la creó.

¿Se puede tener un array de punteros a struct?

Sí: Producto *catalogo[100] es un array de 100 punteros, cada uno apuntando a un Producto asignado independientemente. Es útil cuando las structs tienen tamaños distintos (con herencia simulada por composición) o cuando quieres reubicarlas con realloc sin invalidar los punteros externos.