Results 1 to 10 of 10

Thread: Strange AV?

  1. #1

    Strange AV?

    Hey everyone,

    I'm getting a strange AV. Don't really know why it's popping up.

    Code:
    type
      PMyRec = ^TMyRec;
      TMyRec = record
        Str: String;
        Int: Integer;
      end;
    
    procedure TForm1.Button5Click(Sender: TObject);
    var
      P: PMyRec;
    begin
      GetMem(P, sizeof(TMyRec));
      P^.Str := 'test';   //<< AV HERE!
      P^.Int := 5;
    
      FreeMem(P);
    end;
    This should go fine. I just set the Str which is actually a special kind of pointer, to point to 'test'.

    Can somebody enlighten me?

    Thanks
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  2. #2
    Hmm, strange, because only one line of code is wrong:
    Code:
    FreeMem( P );
    You must free String in record first, like this:
    Code:
    P^.Str := '';
    And only then call FreeMem.

    But... try to call FillChar( P^, SizeOf( P^ ), 0 ) after GetMem

  3. #3
    Hmm.. this is really odd. It does work if I replace getMem() and FreeMem() by New() and Dispose().

    Does anyone know the differences between these functions?

    I'll do some more testing ASAP. Thanks for your reply.

    Edit:

    Code:
      GetMem(P, sizeof(TMyRec));
      FillChar( P^, SizeOf( P^ ), 0 );
      P^.Str := 'test';
      P^.Int := 5;
    This works too. How is that possible?
    Last edited by chronozphere; 11-11-2010 at 07:16 PM.
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  4. #4
    GetMem(P, sizeof(TMyRec));

    results in P, a chunk of allocated memory filled with crap. When you assign a string to this pool of crap you first have to free the old string. If it tries to free Nil then it won't try, but if there's any value but nil, then you are freeing something that isn't allocated

    Basically, you need to use either allocmem(it'll zero out the memory), or use fillchar after getmem. They are basically the same

    Edit: and I think new uses the same method as allocmem. Eg. zeroes before returning
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

  5. #5
    PGDCE Developer de_jean_7777's Avatar
    Join Date
    Nov 2006
    Location
    Bosnia and Herzegovina (Herzegovina)
    Posts
    287
    new and dispose are used with pointers to records or other structures that contain automated types, so they are initialized/finalized properly. Since the string in your example is probably an ansistring, and therefore an automated type, you need to use new and dispose, which I suggest you use instead of getmem/freemem. I only use getmem/freemem for memory which has no type (e.g. plain pointers). As JSoftware said, the compiler will try to free the old string when it assigns the new one, but there is no old string, only garbage which was on the heap where your record got allocated.
    Existence is pain

  6. #6
    Code:
    Str: String;
    is merely a pointer.

    You should define strings with length if you want to use them in data blocks:

    Code:
    Str: String[64];
    I think this is will take 65 bytes but usable like normal string. Just that it can have at max 64 characters if defined like that. You can alternatively use array[1..64] of char;

  7. #7
    That might be an appropriate sollution for me.

    String[64] is basicly a shortstring with a maximum capacity of 64 chars, right?
    Coders rule nr 1: Face ur bugz.. dont cage them with code, kill'em with ur cursor.

  8. #8
    I'm not exactly sure... You might be able to define it like String[4600] but i haven't tested that, not home atm either. At least String[255] should work no problem but you want to keep it as small as possible depending on average string length needed in it. It does reserve the whole space in memory.

  9. #9
    Short strings can have 255 characters maximum, so we can not define string[4600] (at least with older Delphi compilers, I'm not familiar with the latest versions). Calling FillChar(P^, sizeof(TMyRec), 0); after GetMem() will eliminate the problem even without the restriction of the short string.
    Last edited by Jimmy Valavanis; 30-03-2012 at 04:25 PM.

  10. #10
    I just tried your code with Lazarus and it doesn't give AV in objfpc or delphi modes. Works normally. It should be close to same thing as if you define a string variable in a procedure; initial value isn't initialized and when new value is stored, the trashcollector would try to free the old string which doesn't exist and give AV. However procedures do initialize string variables! If you make:
    edit: JSoftware already said the same...
    Code:
    var s: string;
    begin
      memo1.Lines.Add(s);
    It will print just a line chance, it never adds random characters. This however isn't case if you directly assign a memory space for it. Fillchar fixes that.

    string[4600] didn't even compile, max was indeed 255. But this works:
    Code:
    s: array[1..6400] of char;
    ...
    procedure TForm1.FormCreate(Sender: TObject);
    var i: integer;
    begin
      //s:='test'; // This works too with proper cut after 4 characters
      for i:=1 to 6400 do
        s[i]:=inttostr(i mod 10)[1]; 
        // [1] picks first and only character of inttostr() which results as string, expected char
      memo1.Lines.Add(s); // 6400 characters of continuous 0-9
    end;
    Last edited by User137; 12-11-2010 at 02:47 PM.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •