Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Recursive search problem

Status
Not open for further replies.

801119

Programmer
Apr 10, 2000
311
SE
Please take a look at this and tell me why Memo1->Lines->Add(c_Dir); resultst in 7??
It simply refuses to recursive it self as i want it too... perhaps I've overlooked something?

Code:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char *c_Dir = Edit1->Text.c_str();
    char *c_Mask = "*.*";
    Memo1->Lines->Clear();
    ScanDir(Form1,c_Dir,c_Mask);
}

void __fastcall TForm1::ScanDir(TObject *Sender, char *c_Dir, char *c_Mask)
{
    struct ffblk ffblk;
    int done;
    int deep;
    char sTmp[512], sTmp2[512];
    strcpy(sTmp,c_Dir);
    strcat(sTmp,c_Mask);
    done = findfirst( sTmp, &ffblk, FA_DIREC + FA_SYSTEM + FA_HIDDEN + FA_RDONLY + FA_ARCH );
    while( !done  )
    {
        if( strcmp( ".", ffblk.ff_name ) != 0
        &&  strcmp( "..", ffblk.ff_name ) != 0 )
        {
            if( (ffblk.ff_attrib & FA_DIREC) == FA_DIREC )
            {
            strcpy(sTmp2,c_Dir);
            strcat(sTmp2,ffblk.ff_name);
            strcat(sTmp2,"\\");
            Memo1->Lines->Add(c_Dir);
            ScanDir(Form1, sTmp2 , c_Mask);
            }
        }
    done = findnext(&ffblk);
    }
}

My codes look like something a kid wrote
I have absolutely no idea what I am talking about
Somehow I still manage to make it work
 
very curious. it does the 7 thing when i first hit the button but when I hit it again it does not.

tomcruz.net
 
I honestly cant see much difference in the code you wrote and the code below. But this seems to work.
rememberthe memo object wont contain the entire list if the list is to long. you will have to use a richedit.

#include <vcl.h>
#pragma hdrstop

#include <dos.h>
#include <dir.h>

#include &quot;Unit1.h&quot;

#pragma package(smart_init)
#pragma resource &quot;*.dfm&quot;
TForm1 *Form1;

int RecurseDir (char *dir, char *wild, int x);

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
int x = 0;
RecurseDir (&quot;C:\\&quot;, &quot;*.*&quot;, x);
}

char directoryarray [5000] [513];

int RecurseDir (char *dir, char *wild, int x)
{
// Loads the directoryarray

struct ffblk ffblk;
int done;
char buff [512];

strcpy( buff, dir );
strcat( buff, wild );

done = findfirst(buff, &ffblk,
FA_DIREC + FA_SYSTEM
+ FA_HIDDEN + FA_RDONLY + FA_ARCH);

while( !done )
{
if(strcmp(&quot;.&quot;, ffblk.ff_name) != 0 && strcmp(&quot;..&quot;, ffblk.ff_name) != 0)
{
if((ffblk.ff_attrib & FA_DIREC) == FA_DIREC)
{
// process directory
strcpy(buff, dir);
strcat(buff, ffblk.ff_name);
strcpy (directoryarray [x], buff);
Form1->Memo1->Lines->Add (buff);
strcat(buff, &quot;\\&quot;);

x++;

x = RecurseDir(buff, wild, x);
}
else
{
//
}
}

done = findnext(&ffblk);
}

return x;
}

tomcruz.net
 
for some reason I dont like the looks of this

char *c_Dir = Edit1->Text.c_str();
char *c_Mask = &quot;*.*&quot;;

the pointers seem out of place in this instance.

maybe just a personal preference.

tomcruz.net
 
I'll try it as soon as I come home, right now I dont have time.. and the:

char *c_Dir = Edit1->Text.c_str();
char *c_Mask = &quot;*.*&quot;;

:part is only for testing at the moment... I won't use TMemo or TRichEdit when I'm done with it! I'm intending to populate a TreeView

My codes look like something a kid wrote
I have absolutely no idea what I am talking about
Somehow I still manage to make it work
 
void __fastcall TForm1::Button1Click(TObject *Sender)

{char *c_Dir = Edit1->Text.c_str();
char *c_Mask = &quot;*.*&quot;;
Memo1->Lines->Clear();
ScanDir(Form1,c_Dir,c_Mask);
}

This is not good at all,
1) the pointers c_dir and c_mask are local to this subroutine , this means that they are created on the stack and after the subroutine is done they can be overwritten by another local value from another subroutine.

2) c_mask is given the pointer of a string that is also local to the subroutine (&quot;*.*&quot; is made on the stack and can be overwritten afterwards)

better : make c_mask and c_dir global or private pointers and assign memory to them : f.i.


char *c_Dir[256];
char *c_Mask[20];

in your subroutine :
void __fastcall TForm1::Button1Click(TObject *Sender)
{
strcpy(c_Dir,Edit1->Text.c_str());
strcpy(c_Mask,&quot;*.*&quot;);
ScanDir(Form1,c_Dir,c_Mask);
}





Wim Vanherp
Wim.Vanherp@belgacom.net
 
that might explain the 7. as the method 801119 uses to load his parameter list for the scandir function is passing the pointer to the local c_dir.

tomcruz.net
 
Here's what it says in the docs:
AnsiString::c_str() returns a non const temporary pointer to the internal string buffer in the AnsiString object. The pointer is invalid once the statement in which it is used has finished executing.
---

Basically, the pointer is valid until another function needs to use the same temporary storage. It changes somewhere around when findfirst is called in your case.

Try this:
Code:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
    char sTmp[512];
    strcpy(sTmp,Edit1->Text.c_str());
    char *c_Mask = &quot;*.*&quot;;
    Memo1->Lines->Clear();
    ScanDir(Form1,sTmp,c_Mask);
}

Also, in ScanDir, place a findclose(&ffblk) at the very end (outside/after the loop) of the function. I don't think it's absolutely necessary, but it frees up handles used by the OS.

Another thing you might consider is to change
Memo1->Lines->Add(c_Dir);
to
Memo1->Lines->Add(sTmp2);

This will give you the correct list of directories.

Also consider using String's instead of char arrays. This way, although unlikely, you're sure you won't overrun your arrays.

To wimvanherp:
I do not know where you got your info, but this kind of &quot;advice&quot; really scares me. To anyone reading this, I'd like to make a few points. This is not to criticize. It's simply to make sure that people don't get misinformed.

(QUOTE)
1) the pointers c_dir and c_mask are local to this subroutine , this means that they are created on the stack and after the subroutine is done they can be overwritten by another local value from another subroutine.

2) c_mask is given the pointer of a string that is also local to the subroutine (&quot;*.*&quot; is made on the stack and can be overwritten afterwards)
(END QUOTE)

The first statement is unclear. The storage location for the pointers are indeed on the stack/local, but what the pointers point to are not necessarily on the stack. In this case, they are not.

The second statement is false. &quot;*.*&quot; is a constant and is stored in the initialized data section of your code. It's actually global to the whole app (sorta). For more info, you can consult a compiler construction book.

Since he is calling a recursive function, it is perfectly ok to use the pointers as 801119 did. He only got into a snag because of the temporary storage issue.

c_Dir and c_Mask do not point to local data. It's the storage locations for the pointers themselves that's local. So there's no worry about overwriting anything. Even if the data was local, there'd be no problems. As an example, look at my modification above. It has local data. Just don't store that pointer somewhere global, then you'd be correct that the data would get overwritten after Button1Click() returns.

The function you gave as a fix needs a little modification. You're trying to copy a char* into a char**. Remove the '*' in your declarations and you'll be fine.

Hope that helps. And I hope that didn't sound harsh. It wasn't meant to be.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top