Punteros y memoria dinámica | P2 GIR Saltearse al contenido

Punteros y memoria dinámica

Introducción

En P1 (C), para estructuras dinámicas usabas:

  • malloc / realloc para reservar o redimensionar memoria,
  • free para liberarla,
  • punteros para modificar datos fuera de una función (paso “por referencia” con T*).

En P2 (C++), normalmente evitamos gestionar memoria a mano y usamos:

  • std::vector<T> para arrays dinámicos,
  • std::string para texto,
  • RAII (la memoria se libera automáticamente al salir de ámbito).

La idea clave: en C tú gestionas la memoria; en C++ intentamos delegarlo en la biblioteca estándar.


1) Registro dinámico de estudiantes (crece con realloc)

Cada estudiante tiene nombre y calificación. Se almacenan en un array dinámico que crece al añadir.

P1 — C (malloc/realloc/free)

#include <stdio.h>
#include <stdlib.h>
#define TAM_NOMBRE 50
typedef struct {
char nombre[TAM_NOMBRE];
float calificacion;
} TEstudiante;
void agregarEstudiante(TEstudiante **registro, int *numEstudiantes);
void mostrarEstudiantes(TEstudiante registro[], int numEstudiantes);
int main() {
TEstudiante *registro = NULL;
int numEstudiantes = 0;
/* Añadir 3 estudiantes */
for (int i = 0; i < 3; i++) {
agregarEstudiante(&registro, &numEstudiantes);
}
mostrarEstudiantes(registro, numEstudiantes);
if (registro != NULL) {
free(registro);
registro = NULL;
}
return 0;
}
void agregarEstudiante(TEstudiante **registro, int *numEstudiantes) {
int num = *numEstudiantes;
*registro = realloc(*registro, (num + 1) * sizeof(TEstudiante));
if (*registro == NULL) {
printf("Error en la reserva de memoria.\n");
} else {
printf("Introduce el nombre del estudiante: ");
scanf("%s", (*registro)[num].nombre);
printf("Introduce la calificación: ");
scanf("%f", &(*registro)[num].calificacion);
*numEstudiantes = num + 1;
}
}
void mostrarEstudiantes(TEstudiante registro[], int numEstudiantes) {
printf("\nRegistro de Estudiantes:\n");
for (int i = 0; i < numEstudiantes; i++) {
printf("Estudiante: %s, Calificación: %.2f\n",
registro[i].nombre, registro[i].calificacion);
}
}

P2 — C++

#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
struct Estudiante {
std::string nombre;
double calificacion;
};
void agregarEstudiante(std::vector<Estudiante>& registro);
void mostrarEstudiantes(const std::vector<Estudiante>& registro);
int main() {
std::vector<Estudiante> registro;
// Añadir 3 estudiantes
for (int i = 0; i < 3; i++) {
agregarEstudiante(registro);
}
mostrarEstudiantes(registro);
// No hace falta free(): el vector se libera solo al salir de main
return 0;
}
void agregarEstudiante(std::vector<Estudiante>& registro) {
Estudiante e;
std::cout << "Introduce el nombre del estudiante: ";
std::cin >> e.nombre;
std::cout << "Introduce la calificación: ";
std::cin >> e.calificacion;
registro.push_back(e);
}
void mostrarEstudiantes(const std::vector<Estudiante>& registro) {
std::cout << "\nRegistro de Estudiantes:\n";
std::cout << std::fixed << std::setprecision(2);
for (const auto& e : registro) {
std::cout << "Estudiante: " << e.nombre
<< ", Calificación: " << e.calificacion << "\n";
}
}

2) Registro dinámico de robots con nombres en memoria dinámica

Este ejemplo muestra dos niveles de memoria dinámica en C:

- el array dinámico de robots (con realloc)
- cada nombre con malloc y free

En C++ esto se simplifica usando std::string (memoria automática) y std::vector.

P1 — C

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *nombre;
float nivelBateria;
} TRobot;
typedef struct {
TRobot *robots;
int cantidad;
} TRegistroRobots;
void inicializarRegistro(TRegistroRobots *registro);
void agregarRobot(TRegistroRobots *registro, char nombre[], float nivelBateria);
void mostrarRobots(TRegistroRobots registro);
void liberarRegistro(TRegistroRobots *registro);
int main() {
TRegistroRobots registro;
char nombre[100];
float nivelBateria;
bool continuar = true;
inicializarRegistro(&registro);
printf("Añadiendo robots (Introduce 'fin' para terminar)...\n");
while (continuar) {
printf("Introduce el nombre del robot (o 'fin' para terminar): ");
scanf("%s", nombre);
if (strcmp(nombre, "fin") == 0) {
continuar = false;
} else {
printf("Introduce el nivel de batería del robot: ");
scanf("%f", &nivelBateria);
agregarRobot(&registro, nombre, nivelBateria);
}
}
mostrarRobots(registro);
liberarRegistro(&registro);
return 0;
}
void inicializarRegistro(TRegistroRobots *registro) {
registro->robots = NULL;
registro->cantidad = 0;
}
void agregarRobot(TRegistroRobots *registro, char nombre[], float nivelBateria) {
int nuevaCantidad = registro->cantidad + 1;
registro->robots = realloc(registro->robots, nuevaCantidad * sizeof(TRobot));
if (registro->robots == NULL) {
printf("Error en la reserva de memoria.\n");
} else {
registro->robots[nuevaCantidad - 1].nombre =
malloc((strlen(nombre) + 1) * sizeof(char));
if (registro->robots[nuevaCantidad - 1].nombre == NULL) {
printf("Error en la reserva de memoria para el nombre.\n");
} else {
strcpy(registro->robots[nuevaCantidad - 1].nombre, nombre);
registro->robots[nuevaCantidad - 1].nivelBateria = nivelBateria;
registro->cantidad = nuevaCantidad;
}
}
}
void mostrarRobots(TRegistroRobots registro) {
printf("\nLista de robots:\n");
for (int i = 0; i < registro.cantidad; i++) {
printf("Robot: %s, Nivel de batería: %.2f%%\n",
registro.robots[i].nombre,
registro.robots[i].nivelBateria);
}
}
void liberarRegistro(TRegistroRobots *registro) {
for (int i = 0; i < registro->cantidad; i++) {
free(registro->robots[i].nombre);
}
if (registro->robots != NULL) {
free(registro->robots);
registro->robots = NULL;
}
registro->cantidad = 0;
}

P2 — C++

#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
struct Robot {
std::string nombre;
double nivelBateria;
};
void agregarRobot(std::vector<Robot>& registro);
void mostrarRobots(const std::vector<Robot>& registro);
int main() {
std::vector<Robot> registro;
std::cout << "Añadiendo robots (Introduce 'fin' para terminar)...\n";
while (true) {
Robot r;
std::cout << "Introduce el nombre del robot (o 'fin' para terminar): ";
std::cin >> r.nombre;
if (r.nombre == "fin") break;
std::cout << "Introduce el nivel de batería del robot: ";
std::cin >> r.nivelBateria;
registro.push_back(r);
}
mostrarRobots(registro);
// No hay liberarRegistro(): vector/string liberan automáticamente
return 0;
}
void agregarRobot(std::vector<Robot>& registro) {
Robot r;
std::cin >> r.nombre >> r.nivelBateria;
registro.push_back(r);
}
void mostrarRobots(const std::vector<Robot>& registro) {
std::cout << "\nLista de robots:\n";
std::cout << std::fixed << std::setprecision(2);
for (const auto& r : registro) {
std::cout << "Robot: " << r.nombre
<< ", Nivel de batería: " << r.nivelBateria << "%\n";
}
}

Ideas clave

  • En C, cuando usas memoria dinámica:

    • cada malloc/realloc debe comprobarse,

    • cada malloc debe tener su free,

    • si hay punteros dentro de structs, hay que liberar “por niveles”.

  • En C++:

    • std::vector sustituye a “array dinámico + realloc”.

    • std::string sustituye a char* con malloc.

    • la liberación es automática si utilizas std::vector y std::string (utilizan el patrón RAII).