Board index » delphi » Problem freeing memory, invalid pointer operation

Problem freeing memory, invalid pointer operation

I add items (which are file names) from a filelistbox to a listbox
(named ListBoxFolders) using the next code:

{----------code snippet}

var li_tel : integer;
    ls_filename, ls_fullpath : string;
    lp_FullPath : pointer;
begin
  ListBoxFolders.Clear;
  For li_tel := 0 to Filelistbox.Items.Count-1 do
  begin
    ls_filename := Filelistbox.Items[li_tel]);
    ls_fullpath := as_dirname+'\'+ls_filename;
    GetMem(lp_FullPath,Length(ls_fullpath)+1);
    lp_FullPath := pointer(StrPcopy(lp_FullPath,ls_FullPath));
    ListBoxFolders.Items.AddObject(ls_filename,lp_FullPath);
  end;
end;

This works fine. In another piece of code I remove items from that
listbox when they have been selected.

{----------code snippet}

var li_seltel, li_index, li_TotalSelected : integer;
    ls_FullPath : string;
    lp_FullPath : pointer;
begin
  with FileListBox do
  begin
    li_TotalSelected := SelCount;
    li_SelTel := 0;
    li_Index := 0;
    while li_SelTel < li_TotalSelected do
    begin
      if selected[li_index] then
      begin
        ls_FullPath := string(Items.Objects[li_index]);
        lp_FullPath := Items.Objects[li_index];
        Items.Delete(li_index);
        Freemem(lp_FullPath,length(ls_FullPath));
        inc(li_SelTel);
      end
      else
        inc(li_index);
    end;
  end;
end;

This seems to work okay at first, I can remove several items. At a
certain moment freemem causes an error "invalid pointer operation".

Three questions:
- What am I doing wrong?

- The sequence of Items.delete and freemem does it matter? I suppose
you should free the memory after deleting the item.

- Is Items.Objects[li_index] the same as
pointer(pchar(Items.Objects[li_index])) in the second snippet?

Any help is very much appreciated.
Daniel

 

Re:Problem freeing memory, invalid pointer operation


   Try deleting the items in reverse order (ie with a dec loop
instead of an inc loop.)

    If you have a list ABC and you delete the first item you
have BC left. Now when you delete the second item you're
deleting the C, and B remains. When you delete the third
item there _is_ no third item...

In article <398d1d84.7487...@news.hetnet.nl>,

Quote
  dmaarte...@hotmail.com wrote:
> I add items (which are file names) from a filelistbox to a listbox
> (named ListBoxFolders) using the next code:

> {----------code snippet}

> var li_tel : integer;
>     ls_filename, ls_fullpath : string;
>     lp_FullPath : pointer;
> begin
>   ListBoxFolders.Clear;
>   For li_tel := 0 to Filelistbox.Items.Count-1 do
>   begin
>     ls_filename := Filelistbox.Items[li_tel]);
>     ls_fullpath := as_dirname+'\'+ls_filename;
>     GetMem(lp_FullPath,Length(ls_fullpath)+1);
>     lp_FullPath := pointer(StrPcopy(lp_FullPath,ls_FullPath));
>     ListBoxFolders.Items.AddObject(ls_filename,lp_FullPath);
>   end;
> end;

> This works fine. In another piece of code I remove items from that
> listbox when they have been selected.

> {----------code snippet}

> var li_seltel, li_index, li_TotalSelected : integer;
>     ls_FullPath : string;
>     lp_FullPath : pointer;
> begin
>   with FileListBox do
>   begin
>     li_TotalSelected := SelCount;
>     li_SelTel := 0;
>     li_Index := 0;
>     while li_SelTel < li_TotalSelected do
>     begin
>       if selected[li_index] then
>       begin
>         ls_FullPath := string(Items.Objects[li_index]);
>         lp_FullPath := Items.Objects[li_index];
>         Items.Delete(li_index);
>         Freemem(lp_FullPath,length(ls_FullPath));
>         inc(li_SelTel);
>       end
>       else
>         inc(li_index);
>     end;
>   end;
> end;

> This seems to work okay at first, I can remove several items. At a
> certain moment freemem causes an error "invalid pointer operation".

> Three questions:
> - What am I doing wrong?

> - The sequence of Items.delete and freemem does it matter? I suppose
> you should free the memory after deleting the item.

> - Is Items.Objects[li_index] the same as
> pointer(pchar(Items.Objects[li_index])) in the second snippet?

> Any help is very much appreciated.
> Daniel

--
Oh, dejanews lets you add a sig - that's useful...

Sent via Deja.com http://www.deja.com/
Before you buy.

Re:Problem freeing memory, invalid pointer operation


Found already out what was wrong...

(ls_FullPath in second part must be of type pchar, not string)

Daniel

On Sat, 05 Aug 2000 13:58:50 GMT, dmaarte...@hotmail.com (Dani?l

Quote
Maartense) wrote:
>I add items (which are file names) from a filelistbox to a listbox
>(named ListBoxFolders) using the next code:

>{----------code snippet}

>var li_tel : integer;
>    ls_filename, ls_fullpath : string;
>    lp_FullPath : pointer;
>begin
>  ListBoxFolders.Clear;
>  For li_tel := 0 to Filelistbox.Items.Count-1 do
>  begin
>    ls_filename := Filelistbox.Items[li_tel]);
>    ls_fullpath := as_dirname+'\'+ls_filename;
>    GetMem(lp_FullPath,Length(ls_fullpath)+1);
>    lp_FullPath := pointer(StrPcopy(lp_FullPath,ls_FullPath));
>    ListBoxFolders.Items.AddObject(ls_filename,lp_FullPath);
>  end;
>end;

>This works fine. In another piece of code I remove items from that
>listbox when they have been selected.

>{----------code snippet}

>var li_seltel, li_index, li_TotalSelected : integer;
>    ls_FullPath : string;
>    lp_FullPath : pointer;
>begin
>  with FileListBox do
>  begin
>    li_TotalSelected := SelCount;
>    li_SelTel := 0;
>    li_Index := 0;
>    while li_SelTel < li_TotalSelected do
>    begin
>      if selected[li_index] then
>      begin
>        ls_FullPath := string(Items.Objects[li_index]);
>        lp_FullPath := Items.Objects[li_index];
>        Items.Delete(li_index);
>        Freemem(lp_FullPath,length(ls_FullPath));
>        inc(li_SelTel);
>      end
>      else
>        inc(li_index);
>    end;
>  end;
>end;

>This seems to work okay at first, I can remove several items. At a
>certain moment freemem causes an error "invalid pointer operation".

>Three questions:
>- What am I doing wrong?

>- The sequence of Items.delete and freemem does it matter? I suppose
>you should free the memory after deleting the item.

>- Is Items.Objects[li_index] the same as
>pointer(pchar(Items.Objects[li_index])) in the second snippet?

>Any help is very much appreciated.
>Daniel

Re:Problem freeing memory, invalid pointer operation


"Dani?l Maartense" <dmaarte...@hotmail.com> skrev i melding
news:398e48e2.1860339@news.hetnet.nl...

Quote
> >I add items (which are file names) from a filelistbox to a listbox
> >(named ListBoxFolders) using the next code:

> >{----------code snippet}

> >var li_tel : integer;
> >    ls_filename, ls_fullpath : string;
> >    lp_FullPath : pointer;
> >begin
> >  ListBoxFolders.Clear;
> >  For li_tel := 0 to Filelistbox.Items.Count-1 do
> >  begin
> >    ls_filename := Filelistbox.Items[li_tel]);
> >    ls_fullpath := as_dirname+'\'+ls_filename;
> >    GetMem(lp_FullPath,Length(ls_fullpath)+1);
> >    lp_FullPath := pointer(StrPcopy(lp_FullPath,ls_FullPath));
> >    ListBoxFolders.Items.AddObject(ls_filename,lp_FullPath);
> >  end;
> >end;

You May actually do it a bit easier:

var li_tel : integer;
    ls_filename,
    ls_fullpath : string;
begin
  ListBoxFolders.Clear;
  For li_tel := 0 to Filelistbox.Items.Count-1 do
  begin
    ls_filename := Filelistbox.Items[li_tel]);
    ls_fullpath := as_dirname+'\'+ls_filename;
    with ListBoxFolders.Items do begin
      Add(ls_filename);
      Objects[Count-1]:=TObject(ls_FullPath);
    end;
  end;
end;

...and, when freeing:

var li_seltel, li_index, li_TotalSelected : integer;
begin
  with FileListBox do
  begin
    li_TotalSelected := SelCount;
    li_SelTel := 0;
    li_Index := 0;
    while li_SelTel < li_TotalSelected do
    begin
      if selected[li_index] then
      begin
        string(Items.Objects[li_index]):=''; // This frees all string's
memory
        Items.Delete(li_index);
        inc(li_SelTel);
      end
      else
        inc(li_index);
    end;
  end;
end;

The secret is, when assigning a '' to a string variable, the string is freed
up, and pointer(EmptyStringVariable) says a NIL pointer.

--
Bjoerge Saether
Consultant / Developer
Asker, Norway
bsaether.removet...@online.no (remove the obvious)

Re:Problem freeing memory, invalid pointer operation


Quote
"Dani?l Maartense" <dmaarte...@hotmail.com> wrote:
> I add items (which are file names) from a filelistbox to a listbox
> (named ListBoxFolders) using the next code:

--cut--

You pass a pointer to AddObject method but you should pass a class. Delphi
assumes this is a class and that's why there are problems when freeing it.
In my opinion there will be much easier to create a small class:

TFileInfo=class
  FullPath:string;
end;

and pass it to AddObject instead of this pointer. In such case you needn't
to free memory when deleting an item and also you don't have to do
typecasting to convert null terminated string to delphi string. BTW I think
it is much safer to use StrPas function instead to typecasting to string
because lp_FullPath is in fact a typical null-terminated string.

Hope this helps.

--
PSky

->p...@polbox.com
->p...@stud.ics.p.lodz.pl

Re:Problem freeing memory, invalid pointer operation


In article <4QZj5.6514$FO3.163...@news.tpnet.pl>, "PSky" <p...@polbox.com>
writes:

Quote
>You pass a pointer to AddObject method but you should pass a class.

The Objects of TStrings (ie of ListBox.Items)  is a DWord which is typed as a
TObject, but can be _any_ 4-byte value. However because Delphi is strongly
typed then you must typecast any non-TObject when you store it, and when you
use it.

Quote
> Delphi assumes this is a class and that's why there are problems
> when freeing it.

AFAIK there are _no_ other direct implications of using the Objects storage for
another type of 4-byte value.

Quote
>In my opinion there will be much easier to create a small class:

>TFileInfo=class
>  FullPath:string;
>end;

>and pass it to AddObject instead of this pointer. In such case you needn't
>to free memory when deleting an item and also you don't have to do
>typecasting to convert null terminated string to delphi string.

But you _would_ have to Create and Free the TFileInfo for each Object, and you
_would_ have to typecast the Object to a TFileInfo. OTOH this is a simple way
to get persistent strings, although trashing OO principles. If you just
typecast the string to a TFileInfo object then you are making assumptions about
the structures of objects which may change and which I (and many others) don't
know about.

Quote
>BTW I think
>it is much safer to use StrPas function instead to typecasting to string
>because lp_FullPath is in fact a typical null-terminated string.

Delphi Help says of StrPas() :-

"Description

This function is provided for backwards compatibility only. To convert a null
terminated string to a Pascal style string, use a typecast or an assignment."

In article <398d1d84.7487...@news.hetnet.nl>, dmaarte...@hotmail.com (Dani?l

Quote
Maartense) writes:
>Three questions:
>- What am I doing wrong?

I don't think David's comment is the answer. While complicated, your use of an
"unselected index" and a "selected count" works OK (AFAIC see). However, using
. . .

  with FileListBox do
    for i := Items.Count - 1 down to 0
      if Selected[i] then begin
        FreeMem(Items.Objects[i]);
        Items.Delete[i];
      end;

       .. is IMO a much clearer way of dealing with this type of situation.

For your initialisation of the listbox, note that StrPCopy() (in D3) only
copies up to 255 characters. Windows MAX_PATH = 260, and might cause a subtle
bug with deep directory structures.

Quote
>- The sequence of Items.delete and freemem does it matter? I suppose
>you should free the memory after deleting the item.

Provided you have a reference to the memory it does not matter. Freeing the
memory first saves you having to store the reference (see above recommended
code).

Note that FreeMem does not need a second parameter, and (according to Delphi
help) could {*word*88} if you provide a different value than when you allocated the
memory, although it does not appear to do so in your case.

Quote
>- Is Items.Objects[li_index] the same as
>pointer(pchar(Items.Objects[li_index])) in the second snippet?

Yes in respect to values, maybe not in respect of the effect of your usage on
Delphi's type-checking.

In article <%3jj5.2509$aK5.39...@news1.online.no>, "Bj?rge S?ther"

Quote
<REMOVE_bsaether@THIS_online.no> writes:
>    ls_filename := Filelistbox.Items[li_tel]);
>    ls_fullpath := as_dirname+'\'+ls_filename;
>    with ListBoxFolders.Items do begin
>      Add(ls_filename);
>      Objects[Count-1]:=TObject(ls_FullPath);

Would this work, and would this make the string contents of string ls_FullPath
persistent. As I understand it the memory for each loop iteration ls_FullPath
would not be new-allocated, so the same location would be pointed to by all the
Objects. And wouldn't ls_FullPath string memory (ie that pointed to by Objects)
be freed when it goes out of scope ?

Alan Lloyd
alangll...@aol.com

Other Threads