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 Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Pointers!. Copy of a string seems to point to original string

Status
Not open for further replies.

johncp

Technical User
Aug 28, 2005
47
GB
Folks

I have written a bubble sort routine to display AnsiString strings in alphabetical order (yes I know standard sort routines exist in TList etc).

The routine copies the AnsiStrings to char strings, squeezes out the non alphabet letters from the char strings, compares the char strings & reorders the AnsiStrings accordingly. It works fine with one big exception. The chars squeezed from the char strings are also removed from the AnsiStrings !.

Do I have a problem with pointers in that cs1 is pointing to dlldescriptors ?. Under debug the addresses of cs1/2 and *(dlldescriptors+i) are different

Where am I going wrong ?

John
//-------------------------------------------------------------------------
//IDE is CBuilder2007
//This funct. sorts & displays dll descriptors in a StringGrid
int displaydlls(int no_dlls, TObject *Sender)
{
String *dlldescriptors ;
dlldescriptors = new String[no_dlls];//AnsiString array to be bubble sorted alphabetically

//interrogate each dll to populate the dll descriptors String array
for(int i=0;i<no_dlls;)
{ //ufo->dllpaths is a AnsiString array of directory paths in ufo
dllhandle = LoadLibrary( (*(ufo->dllpaths + i)).c_str() ) ;
pflabel = (text)GetProcAddress(dllhandle, "_flabel") ;
}

//bubble sort descriptors prior to displaying in StringGrid
int depth = no_dlls -1 ;
char *cs1, *cs2 ;

while(depth>=0)
{
for(int i=0;i<depth;i++)
{
cs1 = (*(dlldescriptors+i)).c_str() ; //Is problem here ?
cs2 = (*(dlldescriptors+i+1)).c_str() ;

int j=0;
do //squeeze out non alphabetical chars from string prior to strcmpi-ing
{
if (!(((cs1[j] >= 'A') && (cs1[j] <= 'Z')) || ((cs1[j]>= 'a') && (cs1[j]<= 'z'))))
for(int k= j;cs1[k]!='\0';k++) cs1[k] = cs1[k+1];
else j++ ;
}
while(cs1[j]!='\0') ;

j=0;
do
{
if (!(((cs2[j] >= 'A') && (cs2[j] <= 'Z')) || ((cs2[j]>= 'a') && (cs2[j]<= 'z'))))
for(int k= j;cs2[k]!='\0';k++) cs2[k] = cs2[k+1];
else j++ ;
}
while(cs2[j]!='\0') ;

if(strcmpi(cs2, cs1)<0) //from string.h
{
String stemp = (*(dlldescriptors+i)) ;
(*(dlldescriptors+i)) = (*(dlldescriptors+i+1)) ;
(*(dlldescriptors+i+1)) = stemp ;
}
}
depth-- ;
}

//write out the descriptors to the StringGrids
for(int i=0;i<no_dlls;i++) Form5->StringGrid1->Cells[0] = *(dlldescriptors+i) ;

delete[] dlldescriptors ;
return 0 ;
}
 
Sorry - in my 1st post a line of code got lost. It is not relevant to the problem but

dllhandle = LoadLibrary((*(ufo->passivedllpaths+i)).c_str());
pflabel = (text)GetProcAddress(dllhandle, "_flabel") ;

should read

dllhandle = LoadLibrary((*(ufo->passivedllpaths+i)).c_str());
pflabel = (text)GetProcAddress(dllhandle, "_flabel") ;
*(passivedlldescriptors + i++) = pflabel() ;

Rgds john
 
Just a quick look at the code it seems like you are setting the address of cs1 to dlldescriptors+i even though they occupy different memory addresses (according to debug). So whatever happens to one happens to the other. Pointers still tend to confuse me.

One way to test that is to copy dlldescriptors to a another temp String and set cs1 to that.

Just out of curiosity, why use char arrays and pointers? Why not do everything in strings?



James P. Cottingham
-----------------------------------------
[sup]I'm number 1,229!
I'm number 1,229![/sup]
 
Hi James

"Just a quick look at the code it seems like you are setting the address of cs1 to dlldescriptors+i even though they occupy different memory addresses (according to debug)."

Correct. I now realise I created 2 pointers in different locations, each pointing to my dlldescriptors. An AnsiString array under debug looks exactly like a char array (just the chars appended '\0', ie AnsiString.c_str()= AnsiString) so if I remove a char from the char array I am removing the same char from the AnsiString array.

"One way to test that is to copy dlldescriptors to a another temp String and set cs1 to that."

I tried this but the new array must be declared with 'new' which returns a pointer which on assignment just points to dlldescriptors.

Dynamic arrays of char whose size is determined at run time must be declared on the heap with new. This returns a pointer and assigning to this pointer just sets it to point at the assigned array. This must be a text book problem but I haven't googled a solution yet. strcopy() & memcpy() don't help. I haven't look at vectors but anyway there must a simpler solution. I'll post when I have it.

John



 
I really like vectors and its close cousins. I haven't mastered them yet but they work very well.

I'll look around for a bubble sort that might work better and to see how how I've handled this in the past.



James P. Cottingham
-----------------------------------------
[sup]I'm number 1,229!
I'm number 1,229![/sup]
 
James

The solution to my pointer problem & creating separate copies of strings was simple eventually.

1. create dynamic char array on heap for temp storage (cs1 = new char[len1+1])
2. copy chars, one at a time, from one string to the other

James asked "Just out of curiosity, why use char arrays and pointers? Why not do everything in strings?"

I assume strings means AnsiStrings, so the answer is
a. Strcmpi takes char strings, not (Ansi)Strings
b. char number n in string cs can be accessed by cs[n] but
Strings need .SubString(n,1) which is slightly more complicated and maybe slower


The code (boiled down) with the bubble sort becomes

#define String AnsiString //library def
HINSTANCE dllhandle ; //"handle" of current DLL
String *dlldescriptors ; //ptr to array of DLL descriptors for sorting alphabetically
dlldescriptors = new String[no_dlls] ; //no_dlls is number of DLLs found

for(int i=0;i<no_dlls;)
{ //interrogate each DLL to load its descriptor
dllhandle = LoadLibrary( (*(dllpaths + i)).c_str() ) ; //dllpaths is String array of dir. paths
pflabel = (text)GetProcAddress(dllhandle, "_flabel") ; //flabel is string descriptor in each DLL
*(dlldescriptors + i++) = pflabel() ; //write descriptor to String array
}

int depth, j, len1, len2 ;
depth = no_dlls-1 ;
char *cs1, *cs2 ;
String schar ;

while(depth>=0)
{
for(int i=0;i<depth;i++)
{
len1 = (*(dlldescriptors+i)).Length() ; //get length of descriptor
len2 = (*(dlldescriptors+i+1)).Length() ; //ditto next descriptor

cs1 = new char[len1+1] ; //create dynamic char array on heap for temp storage
cs2 = new char[len2+1] ; //+1 cos Length() doesn't include the '\0' when counting the chars

for(j=0;j<=len1;j++)
{ //copy each char from the descriptors String array to a temp String grid
schar = (*(dlldescriptors+i)).SubString(j+1,1) ; //beware, SubString indexes from 1
cs1[j] = *(schar.c_str()) ; //and set cs1 to point to new String array
}
for(j=0;j<=len2;j++)
{
schar = (*(dlldescriptors+i+1)).SubString(j+1,1) ;
cs2[j] = *(schar.c_str()) ;
}

j=0;
do //remove chars from cs1 that are not to be included in the bubble sort
{
if (!(((cs1[j] >= 'A') && (cs1[j] <= 'Z')) || ((cs1[j]>= 'a') && (cs1[j]<= 'z'))))
for(int k= j;cs1[k]!='\0';k++) cs1[k] = cs1[k+1];
else j++ ;
}
while(cs1[j]!='\0') ;

j=0;
do
{
if (!(((cs2[j] >= 'A') && (cs2[j] <= 'Z')) || ((cs2[j]>= 'a') && (cs2[j]<= 'z'))))
for(int k= j;cs2[k]!='\0';k++) cs2[k] = cs2[k+1];
else j++ ;
}
while(cs2[j]!='\0') ;

if(strcmpi(cs2, cs1)<0) //char compare of cs1 and cs2 and swap or not
{
String stemp = (*(dlldescriptors+i)) ;
(*(dlldescriptors+i)) = (*(dlldescriptors+i+1)) ;
(*(dlldescriptors+i+1)) = stemp ;
}
delete[] cs1 ; //delete array of char
delete[] cs2 ;
}
depth-- ;
}

//write out descriptors to StringGrid for viewing
for(int i=0;i<no_dlls;i++) Form5->StringGrid1->Cells[0] = *(dlldescriptors+i) ;

delete[] dlldescriptors ; //delete array of pointers to String

John
 
OK. I understand but on the other hand, you don't have to use Strcmpi to compare Strings. Also, you can pull characters from String via [x]. For example String Mystr = "A new string" then MyStr[3] would equal 'n' (note AnsiStrings start with 1 and not 0).


James P. Cottingham
-----------------------------------------
[sup]I'm number 1,229!
I'm number 1,229![/sup]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top