Working with Blocks of Memory


To allocate and work with a custom block of memory, you have to use the GetMem and FreeMem procedures. Both procedures take two parameters: the pointer that is to be associated with the allocated block of memory and an integer that specifies how many bytes of memory to allocate. You don't have to pass the second parameter when you call FreeMem. If you do, you have to make sure that you pass the value that matches the number of bytes allocated with the GetMem call.

The following example shows how to use the BlockRead procedure to read an entire text file into a dynamically allocated block of memory.

Listing 9-3: Loading a file into a dynamically allocated memory block

image from book
program Project1; {$APPTYPE CONSOLE} uses   SysUtils; procedure ReadFile(var P: Pointer; const AFileName: string); var   Src: file;   BytesRead: Integer;   BufferPos: Pointer; begin   AssignFile(Src, AFileName);   {$I-}   Reset(Src, 1);   {$I+}   if IOResult = 0 then   begin     if P <> nil then FreeMem(P);     { release old data }     GetMem(P, FileSize(Src));        { allocate memory for the file }     BytesRead := -1;     BufferPos := P;     while BytesRead <> 0 do     begin       BlockRead(Src, BufferPos^, 1024, BytesRead);       Inc(Integer(BufferPos), BytesRead);     end;     CloseFile(Src);   end;          // if IOResult end; procedure RemoveFile(var P: Pointer); begin   FreeMem(P);   P := nil; end; var   FilePtr: Pointer; begin   ReadFile(FilePtr, 'c:\data.txt');   WriteLn(string(FilePtr));   RemoveFile(FilePtr);   ReadLn; end.
image from book

The code for loading the file into memory is located in the ReadFile procedure. Before allocating a new memory block, the procedure has to determine if the pointer passed as the P parameter already points to a memory block. If it does, we have to release the old memory block. If we forget to release the old file from memory, we will have a huge memory leak.

if P <> nil then FreeMem(P); { release old data }

The GetMem procedure uses the FileSize function to determine the exact number of bytes needed to hold the entire file in memory. After the memory is allocated, we can start reading the file into memory.

Probably the strangest part of the procedure is the local BufferPos pointer. Before we start reading the file in the while loop, we assign the P pointer to the BufferPos pointer.

BufferPos := P; 

The BufferPos pointer points to the exact location in memory where the BlockRead procedure has to store the 1,024 bytes it reads from the file.

BlockRead(Src, BufferPos^, 1024, BytesRead);

After the BlockRead procedure stores the 1,024 bytes to the memory block, we have to update the BufferPos pointer. If we forget to update the pointer, the BlockRead procedure will read the entire file but will also overwrite the old data with the latest 1,024 bytes from the file.

When the BlockRead procedure reads 1,024 bytes, we have to tell the BufferPos pointer to point to the following 1,024 bytes in memory. This is done by typecasting the BufferPos pointer to Integer and by incrementing the address of the pointer with the number of bytes read from the file.

Inc(Integer(BufferPos), BytesRead);

Without the BufferPos pointer, this procedure wouldn't work. BufferPos enables us to do something that we mustn't do with the variable pointer parameter — modify the location to where the pointer points. If we were to modify the location of the original pointer, each call to BlockRead would leak 1,024 bytes of memory, because the following line would tell the original pointer to point 1,024 farther into the memory block.

To display the entire text file, simply typecast the memory block to a string:

WriteLn(string(FilePtr));

image from book
Figure 9-1: Typecast memory block



Inside Delphi 2006
Inside Delphi 2006 (Wordware Delphi Developers Library)
ISBN: 1598220039
EAN: 2147483647
Year: 2004
Pages: 212
Authors: Ivan Hladni

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net