1

In an array of type TArrayParams that stores records of type TParams, according to the code below, there is a string field that can vary from 1 to 1000. How to check the length (in bytes) of memory that TArrayParams will have?

  TParams = record
     S: String; // Length may vary
     I: Integer;
  end;
  TArrayParams = TArray<TParams>;

var arr: TArrayParams;
    i: Integer;
begin
     SetLength(arr, 2);

     for i := 0 to 1 do
     begin
        arr[i].S := 'my random string.... xyz up to (maybe) 1000';
        arr[i].I   := i;
     end;

     // What is the length (in bytes) of the "arr" array's memory space?
     SizeOf(arr) ??? It Doesn't work...
     Length(arr) ??? It Doesn't work...
     ByteLength(arr) ?? It Doesn't work...
end;
wBB
  • 821
  • 1
  • 18
  • 39
  • You'll have to iterate and total up each record manually. – Jerry Dodge Jul 24 '19 at 13:12
  • That's what I feared I had to do ... – wBB Jul 24 '19 at 13:14
  • What are you going to do with this information? The string contains a meta data block and a null terminator, plus the overhead of the memory manager. What exactly do you even mean by the length in bytes? – David Heffernan Jul 24 '19 at 13:16
  • Suppose my string "S" contains "0123456789". So a record TParams should have length equal: Length (S) + SizeOf (I) = 14. Correct? This is what I mean by "length in bytes". – wBB Jul 24 '19 at 13:38
  • 1
    @wBB A TParams will always be 8 bytes long (in 32 bits exe). A string is a pointer, so it's always 4 bytes. – Ken Bourassa Jul 24 '19 at 13:50
  • OK, so what you actually mean is not "length in bytes". What you mean is for a string, use the number of characters (which is always a smaller number than the number of bytes required to store the string). For other types you mean the number of bytes. And you also want to ignore any padding in the records. That's a rather unusual definition, and I suspect one that has no practical use. I ask one more time. What are you going to do with this information? – David Heffernan Jul 24 '19 at 13:56
  • It is very clear that your question is based on multiple misunderstandings that you have. If you want to move forward, you need to clear them up. And let's start by you giving us the back story as to why you asked the question. That will hopefully reveal useful information that can let us put you back on track. – David Heffernan Jul 24 '19 at 13:57
  • All memory in the array of records must be saved to a TMemoryStream and after that, saved in a file. – wBB Jul 24 '19 at 13:59
  • Not sure why you would save to a memory stream and then a file. Wouldn't it be easier to save directly to a file, and avoid having to hold an entire copy of the array in memory? Once you have code that writes to a stream, you can use that with any type of stream, memory stream or file stream. – David Heffernan Jul 24 '19 at 14:02
  • 1
    Leaving that aside, can you explain why you want to know the size of anything? If you want to write to a stream, don't you just write to a stream? Why does your code need to know the size of anything? – David Heffernan Jul 24 '19 at 14:03
  • Just write the data to the stream and then read the size when you're done. – Jerry Dodge Jul 24 '19 at 14:07
  • @DavidHeffernan, You're really right! It's easier to save directly to file without having to check the length of anything. I was wanting the length of array just to save to MemoryStream (by using MyStream.WriteData). If is possible to save everything straight to file, it's better! How do I save this specific array directly to file? – wBB Jul 24 '19 at 14:13
  • 1
    You can't just blit it to a stream, because the data is not held contiguously. How you save the data depends on your needs. Sometimes a binary approach is good, sometimes you'd be better with XML or JSON. It all depends. You've got quite a few knowledge gaps that need to be plugged before you start coding this for real. – David Heffernan Jul 24 '19 at 14:23
  • I just want (and only that) save to disk everything in the record array, regardless of format (Binary, JSON, XML, etc). Since I know the length of the string field may vary, I asked from the beginning "how to check the length in bytes" of the array. But Ok ... Thank you! – wBB Jul 24 '19 at 14:30
  • Yes, I understand that format is important ... What I meant is that regardless of how the information contained in the array will be saved to the file and regardless of what format this information will be saved in the file, I just need the operation be executed (if possible). – wBB Jul 24 '19 at 14:43
  • OK, I'm out of patience here – David Heffernan Jul 24 '19 at 14:48
  • I agree. Me too... – wBB Jul 24 '19 at 15:33
  • Ken and David tried to explain string payload (character data) is not contained in the memory of the array. Hence, the length/size of the array is of no use for streaming your data. – Sertac Akyuz Jul 24 '19 at 15:54
  • That is clear. What is not clear is: Is there a solution to my question? It's not important to me what form the solution will be created. What is important is to solve the problem. Looking at other posts of other users, there is no objective solution to the problem. Reinterpreting: I need to save specific array of records to memory or directly to file. Is It possible? If isn't possible, no problem, it's OK. – wBB Jul 24 '19 at 16:14
  • See the answers in https://stackoverflow.com/questions/8045886/how-to-write-a-structure-to-a-stream , all of them - not just the accepted one. Also the links in the answers, *and* in the comments... It's not surprising that the discussion here is about length/size of the array, that's because it's what the question is. – Sertac Akyuz Jul 24 '19 at 16:42
  • Of course it is possible to save the information to the file. But the question is not about that. – David Heffernan Jul 24 '19 at 17:47

1 Answers1

1

In the comments you were already told that strings are not stored in the records, so you can't simply use stream.write(record, SizeOf(Record)) to save such a record because that would only write a pointer to the stream that is not valid outside the context of your program. So, you need some other way of storing the data. One option would be text: Since the record only contains a number and a string, you could simply write them as text:

var
  sl: tstringlist;
begin
  sl := tstringlist.create;
  try
    for i := Low(arr) to High(arr) do begin
       sl.Add(Format('%d'#9'%s', [arr[i].I, arr[i].s]));
    end;
    sl.SaveToFile('c:\path\to\filename.txt');
  finally
    sl.Free;
  end;
end;

Please note that this code is completely untested!

The resulting file could be loaded into a text editor or e.g. OpenOffice Calc for display purposes.

If text (actually csv with tab as column separator) is not what you want, you need to be more specific in your question.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
  • This doesn't answer the question that was asked – David Heffernan Jul 24 '19 at 17:46
  • It answers what I understood from the comments, what the actual problem is. I might of course be wrong. – dummzeuch Jul 25 '19 at 14:10
  • Indeed, but this site is a little pedantic about answering the actual question. If you feel you want to answer the question asked in the comments, you should edit the question accordingly, to match what was stated in the comments. That's just how SO works. – David Heffernan Jul 25 '19 at 14:21