pjhayward's Pascal Tutorial |
|
pjhayward.net Home Got a question? Tutorial Home Preparation Lesson One - Sample Program Lesson Two - Program Structure Lesson Three - Data Types and Constants Lesson Four - Variables Lesson Five - Text I/O Lesson Six - Subroutines Lesson Seven - Conditional Statements Lesson Eight - Arrays Lesson Nine - Loops Lesson Ten - Units | How to use pointers in Pascal Pointers in Pascal can either be typed or untyped. An untyped pointer is declared like this: var myPointer:pointer;And that's all there is to it. You can allocate any amount of memory to a single pointer, as long as you've got the space on your program's heap. Typed pointers are different. They point to an instance of some sort of data. Here are some examples:
type
someRecordType=record
data1:integer;
data2:string;
end;
var
intPointer:^integer;
recPointer:^someTypeRecord;
strPointer:^string;
Each of these variables is a pointer, but they're each different, and you can't assign one directly to the other. That's because they're typed, and Pascal is very strict on type compliance when you make assignments. When using the pointer, you can either access the pointer itself, or the data the pointer points to. There are cases when each is useful. To access the pointer itself, just use the pointer variable name. To access the referenced data, you'll need to append a carat to the end of the variable name, like this: var someData:integer; intPointer:^integer; untyped:Pointer; begin someData:=0; new(intPointer); //Allocate some memory - since it's typed, the amount is calculated for you intPointer^:=5; untyped:=intPointer; //note that this shouldn't cause any errors, since an untyped pointer can hold ANY type of pointer. someData:=untyped^; dispose(intPointer); //free memory from a typed pointer end;I also demonstrated how to allocate memory for a typed pointer in that example. While I'm on the subject, here's how to allocate memory for an untyped pointer: var buffer:pointer; size:integer; begin size:=65536; GetMem(buffer,size); //do stuff with buffer^ FreeMem(buffer,size); end;The size parameter is optional in FreeMem, but it's always a good idea to state it explicitly. ALWAYS ALWAYS ALWAYS free your pointers! Pascal is not like Java, C#, and other new languages. You have to pick up your own messes. If you don't, you have a memory leak. The memory remains allocated after the reference to it has been removed, and you've lost all access to that memory until your program exits. A common use of pointers is to create a linked list. Here's a sample unit to start from.
unit simpleLinkedList;
interface
type
//Note that tLinkListNode hasn't been defined yet, but the compiler lets you get away with this. It only works for typed pointers.
pLinkListNode=^tLinkListNode;
tLinkListNode=class
data:string; //change this as needed, add fields, whatever
next:pLinkListNode;
end;
procedure createList;
procedure destroyList;
procedure resetList;
procedure next;
procedure add(newData:string);
procedure replace(newData:string);
procedure insert(newData:string);
procedure remove;
function hasNext:boolean;
function getData:string;
implementation
var
listHead:pLinkListNode;
current:pLinkListNode;
procedure createList;
begin
if listHead <> nil then
destroyList; //clear out the old pointers to make sure we don't leak memory
new(listHead);
listHead^.next:=nil; //always initialize unused pointers to nil
current:=listHead;
end;
procedure destroyList;
begin
resetList;
while current <> nil do begin
//by setting next to nil when the node was created, we ensure that the last node has ^.next = nil.
//That gives us something to check for at the end of the list.
listHead:=current^.next;
dispose(current);
current:=listHead;
end;
end;
procedure resetList;
begin
current:=listHead;
end;
procedure next;
begin
current:=current^.next;
end;
procedure add(newData:string);
begin
while (current^.next <> nil) do
next; //find the last node
new(current^.next);
next; //set current to the new node
current^.next:=nil; //make sure we have nil at the end of the list
current^.data:=newData;
end;
procedure replace(newData:string);
begin
current^.data:=newData;
end;
procedure insert(newData:string);
var
prev,newNode:pLinkListNode;
begin
new(newNode);
newNode^.data:=newData;
prev:=listHead;
if prev = current then begin
newNode^.next:=listHead;
listHead:=newNode;
end else begin
while (prev^.next <> current) do
prev:=prev^.next;
newNode^.next:=current;
prev^.next:=newNode;
end;
end;
procedure remove;
var
prev:pLinkListNode;
begin
prev:=listHead;
if prev = current then begin
listHead:=listHead^.next;
dispose(prev);
end else begin
while (prev^.next <> current) do
prev:=prev^.next;
prev^.next:=current^.next;
dispose(current);
current:=prev^.next;
end;
end;
function hasNext:boolean;
begin
hasNext:=current^.next <> nil;
end;
function getData:string;
begin
getData:=current^.data;
end;
begin
listHead:=nil; //initialize to nil before use
current:=nil;
end.
Obviously, this is missing quite a few safety checks. For example, in a number of these functions, you have no idea whether listHead is nil or a pointer. A better approach would be to make the list node a class. The initialization could then take place in the constructor, and the memory disposal in the destructor.Well, hopefully that gets you started. I believe I'll write up a section on classes and object oriented programming, but not today. Back to Question/Answer list |