PDA

View Full Version : array of byte : how to compute its length



virtual
02-08-2009, 06:33 PM
function getPtrLength(_ptr : PBYTE) : integer;
begin
Result := 0;
while ( _ptr <> NIL ) do
begin
inc(Result);
inc(_ptr);
end;
end;


why this function cause a loop for ever when passed an array of byte

when use it like this


var
ptr , _start : PByte;
begin
getmem(ptr,100);
_start := ptr;
for i := 1 to 100 do
begin
ptr^ := Random(100); // fill our array with random numbers
inc(ptr);
end;
//use our function here
ShowMessage(inttostr(getPtrLength(_start))); // expected result is 100 !! but its not
end.


whats wrong here , thanks

Andreaz
02-08-2009, 08:01 PM
You are looking for a null char, but there is no null char in the array. (You fill all 100 elements with random)

JSoftware
03-08-2009, 03:57 AM
You can't compute the length of an arbitary chunk of memory unless it's explicitly given be the nature of the datastructure or the os/memory manager has that functionality

If it's a nullterminated array of byte, then you simply forget to dereference before checking if it's nil(0). eg:


function getPtrLength(_ptr : PBYTE) : integer;
begin
Result := 0;
while ( _ptr^ <> 0 ) do
begin
inc(Result);
inc(_ptr);
end;
end;
.

And as Andreaz is saying, you don't have any data structure in your array in your example

Colin
03-08-2009, 06:36 AM
function getPtrLength(_ptr : PBYTE) : integer;
begin
Result := 0;
repeat
inc(Result);
inc(_ptr);
until _ptr^ = 0;

//i believe repeat will be better as the cmp instruction should be placed at the end of the loop rather than to waste 1 extra jmp instruction.
end;


var
ptr , _start : PByte;
begin
getmem(ptr,101); //1 end byte
_start := ptr;
for i := 1 to 100 do
begin
ptr^ := Random(100); // fill our array with random numbers
inc(ptr);
end;
ptr^ := 0;
//use our function here
ShowMessage(IntToStr(getPtrLength(_start))); // expected result is 100 !! but its is
end.

User137
03-08-2009, 02:42 PM
// expected result is 100 !! but its is

However ptr^ := Random(100); can also place 0 within the array which would terminate length function early. Unless you manage data so there is no null inside it is more "proper" to store the length within a separate variable or possibly at the beginning of array.

virtual
03-08-2009, 05:39 PM
thanks , all i want to do is calculat the size of a given file manually

so after reading the file

BlockRead(File,_Ptr,size//supose that we know the size already);
// use of the function
filesize := GetPtrLength(_ptr);

you may say why you calculate the size and u know it already

i just want to know how to get the size of a memory file

AthenaOfDelphi
03-08-2009, 09:21 PM
You could always use streams...

TMemoryStream

Then you'll immediately have the 'size' property and you'll still be able read and write in much the same manner.

Colin
04-08-2009, 11:10 AM
// expected result is 100 !! but its is

However ptr^ := Random(100); can also place 0 within the array which would terminate length function early. Unless you manage data so there is no null inside it is more "proper" to store the length within a separate variable or possibly at the beginning of array.


good point i didnt look at that :-[ but either way, you can just add a 1 to the random(100), and when you grab the value from the ptr you just -1, however, if the length is going to be below 255 bytes, just use the first byte to record the length of the data when it is written.

obviously you can also do larger by allocating upto 4 bytes... or even 8 bytes to record datalen

also TMemoryStream is a class, which will most likely be slower, classes are created on the heap (which is slower btw). also he asked how to check manually, using a memory stream would be cheating.

anyways the problem you will have (if you were do check without knowing the size from a header or via api), many files can contain terminators... lol (null chars), exe files for example.

-Colin

User137
04-08-2009, 01:13 PM
I think the original question was already answered, if you have a pointer to array or any data at all, it is not possible to find out its length unless it is terminated and very often it is not.

If you need to know size of a file it is asked from operating system using function provided by API, and same program may not work in Linux or other OS. But i don't honestly know specifics on how files are terminated if they are, and what differences there are in NTFS and FAT32 etc...

KidPaddle
04-08-2009, 01:37 PM
Blockread(file pointer, buffer, max size, var BytesRead)

There is no need for calculating the size, you got them from paramter BytesRead.

Regards
Thomas

Chien
04-08-2009, 01:56 PM
// expected result is 100 !! but its is

However ptr^ := Random(100); can also place 0 within the array which would terminate length function early. Unless you manage data so there is no null inside it is more "proper" to store the length within a separate variable or possibly at the beginning of array.


good point i didnt look at that :-[ but either way, you can just add a 1 to the random(100), and when you grab the value from the ptr you just -1, however, if the length is going to be below 255 bytes, just use the first byte to record the length of the data when it is written.

obviously you can also do larger by allocating upto 4 bytes... or even 8 bytes to record datalen

also TMemoryStream is a class, which will most likely be slower, classes are created on the heap (which is slower btw). also he asked how to check manually, using a memory stream would be cheating.

anyways the problem you will have (if you were do check without knowing the size from a header or via api), many files can contain terminators... lol (null chars), exe files for example.

-Colin


I am not make clear what is the point!
If it is a array, why not use the High(ByteArray) to get the length?
and, as I know, the null char is #0 not 0, I think maybe, there is difference
between #0 and 0., so, if you use Random(100), you may get 0, but you will not
get #0
if you just want to calc the file size when reading a file,
TFileStream is a good choice, just create and read the property 'size'.
If insisting calc the size by you self:

Var
Buffer : array[0..10*1024-1] of char;
i: integer;
totalsize : int64;

begin
totalsize :=0;
//create the TFileStream first....
repeat
i := theFileStream.Read(Buffer,10*1024-1);
totalsize := totalsize + i;
until i < 10*1024-1;
end;

virtual
04-08-2009, 04:23 PM
thanks for the clarification

i understand that i can not find the end of an arbitary chunk of memory even i've the adress of the first element .unless u know its size

i thought that NIL is the default END of any new allocation in memory

Colin
04-08-2009, 08:47 PM
and, as I know, the null char is #0 not 0, I think maybe, there is difference
between #0 and 0., so, if you use Random(100), you may get 0, but you will not
get #0

#0 is pascal specific, it is just for the compiler. #0 meaning char(0) or byte(0) = as u shoud know, there is no such thing as #0 in machine code, it is 0.

#0 = 0, and you can not use high on a byte array that would be dynamic.

@virtual

nil, null or nul are all just human readable code.

-Colin

Chien
05-08-2009, 01:31 AM
and you can not use high on a byte array that would be dynamic.


I usually use following code to do something, it works ok:


procedure dynamicArray(inputParam : array of integer);
Var
i : integer;
begin
for i := 0 to High(inputParam) do
....
end;


Althrough it is dynamic, but the machine can tell you how long it is!

User137
05-08-2009, 09:16 AM
Var
ptr , _start : PByte;
i : integer;
arr: array of integer;
begin
setlength(arr,100);
ptr:=@arr;
_start := ptr;
for i := 1 to 100 do
begin
// fill our array with random numbers...
// except that with this kind of dynamic array which isn't structured
// same way this cannot work, unless ptr:=@arr[0];
// which would be cheating, and if you pass @arr[0] to length function
// you would not be able to use high() anymore
ptr^ := Random(100);

inc(ptr);
end;
...
end;

Colin
05-08-2009, 04:55 PM
and you can not use high on a byte array that would be dynamic.


I usually use following code to do something, it works ok:


procedure dynamicArray(inputParam : array of integer);
Var
i : integer;
begin
for i := 0 to High(inputParam) do
....
end;


Althrough it is dynamic, but the machine can tell you how long it is!




the var is not dynamic, you have by this time already set the length of the array, however, if trying to get the size of the file, without knowing the size of the file, you can not set the length of the array, therfore you would be calling high on an empty array, this is impossible. you need to re-read the previous posts.

-Colin