DMarlon Studio

Lección 9 · 9 de 20

Punteros, New y Dispose · Pascal

Trabaje con punteros en Pascal: direcciones con @, acceso con ^, y memoria dinámica reservada con New y devuelta con Dispose.

Pascal · Punteros, New y Dispose en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un puntero guarda la dirección de un dato, no el dato. PProduct = ^TProduct declara un puntero a TProduct, y PInteger ya viene definido en la RTL. Por convención, los tipos puntero empiezan por P.

`@units` obtiene la dirección de una variable que ya existe, y `pUnits^` sigue el puntero hasta el dato. Por eso pUnits^ := pUnits^ + 5 cambia la propia units, que pasa de 10 a 15. La salida nunca muestra direcciones: cambian en cada ejecución y no dicen nada útil.

`New(item)` reserva en el montón (*heap*) un TProduct nuevo y deja su dirección en item; además inicializa los campos gestionados como Name. A partir de ahí se trabaja con item^.Name e item^.Stock. Restock recibe el puntero y modifica el registro original, no una copia.

`Dispose(item)` devuelve esa memoria. Lo que se reserva con New se libera con Dispose, exactamente una vez; si se olvida, hay una fuga. Después conviene poner el puntero a `nil` para no usar por error una dirección liberada, y `Assigned` comprueba si apunta a algo.

Los objetos de las lecciones anteriores son, por dentro, punteros: Create y Free hacen el papel de New y Dispose. Saber cómo funcionan ayuda a entender por qué asignar un objeto copia solo la referencia.

Código · main.pas

program main;type  TProduct = record    Name: String;    Stock: Integer;  end;  PProduct = ^TProduct;  // a pointer to a TProductprocedure Restock(item: PProduct; amount: Integer);begin  Inc(item^.Stock, amount);  // changes the record it points toend;var  units: Integer;  pUnits: PInteger;  item: PProduct;begin  units := 10;  pUnits := @units;           // the address of an existing variable  pUnits^ := pUnits^ + 5;     // ^ follows the pointer  WriteLn('units = ', units);  item := nil;  WriteLn('Assigned before New: ', Assigned(item));  New(item);                  // a new record on the heap  item^.Name := 'Printer toner';  item^.Stock := 3;  Restock(item, 12);  WriteLn(item^.Name, ': ', item^.Stock, ' in stock');  Dispose(item);              // give the memory back  item := nil;                // and forget the old address  WriteLn('Assigned after Dispose: ', Assigned(item));end.

Salida · fpc main.pas && ./main

units = 15
Assigned before New: FALSE
Printer toner: 15 in stock
Assigned after Dispose: FALSE

Para recordar

  • @x es la dirección de x; p^ es el dato al que apunta p.
  • New reserva memoria en el montón; Dispose la devuelve.
  • Cada New necesita exactamente un Dispose.
  • Tras Dispose, ponga el puntero a nil.
  • Assigned(p) dice si p apunta a algo.

Ejercicio

Cree con New un segundo producto, 'Paper A4' con 40 unidades, escriba la suma de las existencias de los dos y libere ambos con Dispose.