Board index » delphi » Long Strings and the Memory (was: @LStrAsg)

Long Strings and the Memory (was: @LStrAsg)

I am getting very weird string/memory problem in my application writen
exclusively for NT. I have about 40-50 users and only one of them is
reporting this error, and not always, just in about 25% of the time.
She has NT with Service Pack 2 (as I and the other users do) so it
should be NT problems, but who knows. Here is the code:

p is declared as a pointer.

  {$IFOPT D+} Trace('Test 4'); {$ENDIF}
      GetMem(p, SizeOf(string));
  {$IFOPT D+} Trace('Test 5'); {$ENDIF}
      String(p^) := ComboBox1.Text;
  {$IFOPT D+} Trace('Test 6'); {$ENDIF}

She's getting Trace of 'Test 4' properly, then the memory is allocated
(for long string). She's getting Trace of 'Test 5' properly, but She
is not getting Trace of 'Test 6'. On the line String(p^) :=
ComboBox1.Text; she gets thown exception EAccessViolation which is
coming from the routine @LStrAsg . I'm confident, problem is not in
Combobox1.Text but with the assignment. Does anybody experienced such
problem ? How is it that only one user is getting it while all others
are happy ?

Thank you
Lester

lko...@ottawa.com
http://www.{*word*104}us.ca/~lkovac/lester.htm

 

Re:Long Strings and the Memory (was: @LStrAsg)


Quote
Lester Kovac wrote:

> I am getting very weird string/memory problem in my application writen
> exclusively for NT. I have about 40-50 users and only one of them is
> reporting this error, and not always, just in about 25% of the time.
> She has NT with Service Pack 2 (as I and the other users do) so it
> should be NT problems, but who knows. Here is the code:

> p is declared as a pointer.

>   {$IFOPT D+} Trace('Test 4'); {$ENDIF}
>       GetMem(p, SizeOf(string));
>   {$IFOPT D+} Trace('Test 5'); {$ENDIF}
>       String(p^) := ComboBox1.Text;
>   {$IFOPT D+} Trace('Test 6'); {$ENDIF}

> She's getting Trace of 'Test 4' properly, then the memory is allocated
> (for long string). She's getting Trace of 'Test 5' properly, but She
> is not getting Trace of 'Test 6'. On the line String(p^) :=
> ComboBox1.Text; she gets thown exception EAccessViolation which is
> coming from the routine @LStrAsg . I'm confident, problem is not in
> Combobox1.Text but with the assignment. Does anybody experienced such
> problem ? How is it that only one user is getting it while all others
> are happy ?

> Thank you
> Lester

> lko...@ottawa.com
> http://www.{*word*104}us.ca/~lkovac/lester.htm

There are known problems with D2 and NT4.0 Sevice Pack 2.

Check on Dr. Bobs home page for more details.
(http://home.pi.net/~drbob/)

hart.

Re:Long Strings and the Memory (was: @LStrAsg)


If you are using Delphi 2 (which seams to be the case) and you are
using LongStrings then STRING is more or less a PChar. This means it
is a pointer to "some" memory. Therefore SizeOf(String) will return 4
bytes for the "pointer". There for it is NOT valid to write
"String(p^) :=".

Delphi takes care of allocation/deallocation memory when you work with
the string  -  AND THIS IS JUST GREAT :-)  -  You can therefor not
typecast "p" to a string. If you declare a string (longstirng) this
more of less only occupy 4 bytes of memory. When you move something to
this string (P := ComboBox1.Text) Delphi is so "kind" that it
automatic allocates the memory required. YES !!!

I would write your code as this (prefered methode)

Var P : String;
{$IFOPT D+} Trace('Test 4'); {$ENDIF}
{$IFOPT D+} Trace('Test 5'); {$ENDIF}
    P := ComboBox1.Text;
{$IFOPT D+} Trace('Test 6'); {$ENDIF}

or (alt. method);

($IFOPT D+} Trace('Test 4'); {$ENDIF}
    GetMem(p, Length(ComboBox1.Text);
{$IFOPT D+} Trace('Test 5'); {$ENDIF}
    Move(ComboBo1.Text, P, Length(ComboBox1.Text);
    String(p^) := ComboBox1.Text;
{$IFOPT D+} Trace('Test 6'); {$ENDIF}

On Wed, 19 Feb 1997 17:03:08 GMT, lester.ko...@cognos.com (Lester

Quote
Kovac) wrote:
>I am getting very weird string/memory problem in my application writen
>exclusively for NT. I have about 40-50 users and only one of them is
>reporting this error, and not always, just in about 25% of the time.
>She has NT with Service Pack 2 (as I and the other users do) so it
>should be NT problems, but who knows. Here is the code:

>p is declared as a pointer.

>  {$IFOPT D+} Trace('Test 4'); {$ENDIF}
>      GetMem(p, SizeOf(string));
>  {$IFOPT D+} Trace('Test 5'); {$ENDIF}
>      String(p^) := ComboBox1.Text;
>  {$IFOPT D+} Trace('Test 6'); {$ENDIF}

>She's getting Trace of 'Test 4' properly, then the memory is allocated
>(for long string). She's getting Trace of 'Test 5' properly, but She
>is not getting Trace of 'Test 6'. On the line String(p^) :=
>ComboBox1.Text; she gets thown exception EAccessViolation which is
>coming from the routine @LStrAsg . I'm confident, problem is not in
>Combobox1.Text but with the assignment. Does anybody experienced such
>problem ? How is it that only one user is getting it while all others
>are happy ?

>Thank you
>Lester

>lko...@ottawa.com
>http://www.{*word*104}us.ca/~lkovac/lester.htm

Re:Long Strings and the Memory (was: @LStrAsg)


pelle...@post4.tele.dk (Pelle F. S. Liljendal) wrote:

Thank you very much for your reply, Pelle & Hart. According to the
manual long string is 4 byte pointer. When you assing any string to
it, it should automatically take proper space from the memory and
point to it. So it is perfectly OK to allocate only 4 bytes, they are
for pointer only. However, if the string is not declared implicitely
as a string, it is not initialized. So what was happening for that
only one user (and I don't know why, that is probably the matter of
service pack; but bug was clearly mine) that allocated 4 byte space is
not nil (not zero) so it is pointing to some unallocated space. When I
try to assign some string to it, long string think it's not empty and
before it sets itself to new value it tries to deallocate old value -
and that's when it throws an exception. Suprisingly, other users,
including me, are getting allocated space prefilled with 0... Here is
the proper code, how it should be:

      GetMem(p, SizeOf(string));
// pre-fill block of memory with zeros, so that long string is
// initially nil
      Pointer(p^) := nil;
      String(p^) := ComboBox1.Text;

And yes, I need string to be on the heap, because I keep it outside of
this method in the some kind of list. By the way, when you deallocate
this, you must do this:

      String(p^) := EmptyStr;
      FreeMem(p, SizeOf(string));

first line empties (deallocates) strings buffer, while the second
deallocates that 4 bytes space for pointer.

Alt method described by Pelle would work only for strings longer than
4 and if it was more, you would waste memory.

Quote
>If you are using Delphi 2 (which seams to be the case) and you are
>using LongStrings then STRING is more or less a PChar. This means it
>is a pointer to "some" memory. Therefore SizeOf(String) will return 4
>bytes for the "pointer". There for it is NOT valid to write
>"String(p^) :=".
>Delphi takes care of allocation/deallocation memory when you work with
>the string  -  AND THIS IS JUST GREAT :-)  -  You can therefor not
>typecast "p" to a string. If you declare a string (longstirng) this
>more of less only occupy 4 bytes of memory. When you move something to
>this string (P := ComboBox1.Text) Delphi is so "kind" that it
>automatic allocates the memory required. YES !!!
>I would write your code as this (prefered methode)
>Var P : String;
>{$IFOPT D+} Trace('Test 4'); {$ENDIF}
>{$IFOPT D+} Trace('Test 5'); {$ENDIF}
>    P := ComboBox1.Text;
>{$IFOPT D+} Trace('Test 6'); {$ENDIF}
>or (alt. method);
>($IFOPT D+} Trace('Test 4'); {$ENDIF}
>    GetMem(p, Length(ComboBox1.Text);
>{$IFOPT D+} Trace('Test 5'); {$ENDIF}
>    Move(ComboBo1.Text, P, Length(ComboBox1.Text);
>    String(p^) := ComboBox1.Text;
>{$IFOPT D+} Trace('Test 6'); {$ENDIF}

Lester

lko...@ottawa.com
http://www.{*word*104}us.ca/~lkovac/lester.htm

Re:Long Strings and the Memory (was: @LStrAsg)


Quote
Lester Kovac wrote:

>       GetMem(p, SizeOf(string));
> // pre-fill block of memory with zeros, so that long string is
> // initially nil
>       Pointer(p^) := nil;
>       String(p^) := ComboBox1.Text;

>... when you deallocate this, you must do this:

>       String(p^) := EmptyStr;
>       FreeMem(p, SizeOf(string));

You could rewrite this as

var
  p: ^string;
begin
  GetMem(p,SizeOf(string));
  Initialize(p^);  // sets p^ to ''

  p^ := ComboBox1.Text;

  Finalize(p^);    // releases string in p^
  FreeMem(p,SizeOf(string));
// FreeMem(p); would also work... a D2 extension...

This is what Initialize() and Finalize() were designed to do.
Personally, I'm still unclear why you need to declare a pointer
to a string (since a string is already a pointer)- it's so much
easier to write

var
  p: string;
begin
  p := ComboBox1.Text;

Chris.

Re:Long Strings and the Memory (was: @LStrAsg)


On Wed, 19 Feb 1997 17:03:08 GMT, lester.ko...@cognos.com (Lester

Quote
Kovac) wrote:
>p is declared as a pointer.

>  {$IFOPT D+} Trace('Test 4'); {$ENDIF}
>      GetMem(p, SizeOf(string));
>  {$IFOPT D+} Trace('Test 5'); {$ENDIF}
>      String(p^) := ComboBox1.Text;
>  {$IFOPT D+} Trace('Test 6'); {$ENDIF}

It is not obvious to me that this should work at all.  Either you are
up to no good, or this is an advanced construct well beyond my
abilities.

Why is p a pointer and not just a string? (Or at least a PChar).

You can cast from a long string to a pchar for calling the Windows API
etc, but casting a pointer to a string seems to be asking for trouble.
(I am mostly worried about how p is initialized (or not) in the above
example).

Brian

Re:Long Strings and the Memory (was: @LStrAsg)


On Wed, 19 Feb 1997 17:03:08 GMT, lester.ko...@cognos.com (Lester

Quote
Kovac) wrote:
>p is declared as a pointer.

>  {$IFOPT D+} Trace('Test 4'); {$ENDIF}
>      GetMem(p, SizeOf(string));
>  {$IFOPT D+} Trace('Test 5'); {$ENDIF}
>      String(p^) := ComboBox1.Text;
>  {$IFOPT D+} Trace('Test 6'); {$ENDIF}

The assignment just after Test5 should GPF on every system.
A string is some very interesting type in Delphi. The main thing you
must know is that the length information is stored just in front of
the string and that a string always points to the beginning of the
string leading to negative offsets. This assignment should GPF on
every system as I think it modifies the contents of unassigned memory.
The Delphi memory system is however allocating memory in larger spaces
and you might come away with it.
The second problem is "SizeOf (String)" I have not tested the return
value, but it seems that it is not what you want. In fact it is a
pointer or it is of 2GB Size. I just don't know.

Better do it this way:
var
  p : PChar;
begin
  GetMem (p, length (Combo1.Text) + 1);
  StrPCopy (p, Combo1.Text);

 You can use a PChar just like a String in Delphi 2.
If necessary convert it using the StrPas function.
The better solution would be to declare a real string variable.

Quote
>She's getting Trace of 'Test 4' properly, then the memory is allocated
>(for long string). She's getting Trace of 'Test 5' properly, but She
>is not getting Trace of 'Test 6'. On the line String(p^) :=
>ComboBox1.Text; she gets thown exception EAccessViolation which is
>coming from the routine @LStrAsg . I'm confident, problem is not in
>Combobox1.Text but with the assignment.
>Does anybody experienced such problem ?

Yes, I did.

Quote
>How is it that only one user is getting it while all others
>are happy ?

The NT Random GPF-Generator is not working properly on the other
machines :-)

Hope this helps

  Meikel Weber
Make sure you take a look at
http://www.europe.de/cebbs/weber
When replying via E-Mail strip the "-" in my E-Mail address!!

Other Threads