I have a function which creates Pointer to a data from a Stream.
function StreamToByteArray(Stream: TStream): Pointer;
var
ByteArr: array of Byte;
begin
if Assigned(Stream) then
begin
Stream.Position := 0;
SetLength(ByteArr, Stream.Size);
Stream.Read(ByteArr[0], Stream.Size);
end
else
SetLength(ByteArr, 0);
result := @ByteArr[0];
end;
How can I convert it back, from a Pointer to dynamic byte array and
then save the content to a stream. Or maybe it is possible to load stream directly from
a Pointer?
Thanks for help.
Ouch, this code is (unfortunately) very bad. Your function returns a pointer to the ByteArr array, but unfortunately that array runs out of scope when the function exists: you’re essentially returning an Invalid Pointer! Even if the error doesn’t immediately pop up, you’ve got a latent Access Violation in there.
Longer explanation
A
Pointeris a dangerous structure: it doesn’t contain data, it simply says where that data exists. Your example of an untypedPointeris the most difficult kind of Pointer, it says nothing about the data that exists at the given address. It might point towards some bytes you read from a stream, might point to a string or even a picture of some sorts. You can’t even know the amount of data that’s at the given address.The Pointer concept is closely related to the concept of allocating memory. We use many different techniques for allocation memory, using local variables, global variables, objects, dynamic arrays etc. In your sample function you’re using a dynamic array, the
array of Byte. The compiler does a very nice job of shielding you from the internals of allocating and reallocation memory, you can simply useSetLength()to say how big the array should be. Things work pretty well because the dynamic array is a managed data structure in Delphi: the compiler keeps track of how you’re using the dynamic array and will free the associated memory as soon as the dynamic array is no longer needed. As far as the compiler is concerned, the associated memory is no longer required when your function exists.When you’re doing:
You’re essentially taking the address for the compiler-allocated memory block. Since you’re using a very low level structure to do that (the
Pointer), the compiler can’t possibly keep track of your usage of the memory, so it will free the memory when the function exists. That leaves you with a Pointer to un-allocated memory.How to properly return a
Pointerfrom a functionFirst of all you should avoid Pointers if possible: they’re low-level, the compiler can’t help with type-safety or deallocation, they’re simply too easy to get wrong. And when you do get Pointers wrong, the errors are usually Access Violations, and they’re difficult to track.
That said, if you really want to return a pointer, you should return a pointer to explicitly allocated memory, so you know the compiler doesn’t free it for you. When you do that, make sure the receiving code knows it’s responsible for the memory (should free the memory when it’s no longer needed). For example, your function could be re-written like this:
How to change a Pointer back to
array of byteorTStreamThe answer is, there’s no way to change it back. A pointer is just that, a pointer to some random data. An array of byte is more then the data it contains. A
TStreamis even more abstract: it’s an interface that tells you how to retrieve data, it doesn’t necessarily hold any data. For example, aTFileStream(and that is aTStream) doesn’t hold any bytes of data: all the data is in the file on disk.