Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 300
  • Last Modified:

converting a string back to an array, i.e., char*

Inside a method I have equated (converted) a char* to a string.

That is; string str1(s1).  Array s1 is a char*, and after I manipulate the string- str1, I want to equate it to s4.  s4 is an array of char*.

Without submitting the code, I hope I made myself clear.
For a Friday afternoon/evening I hope some will answer this question.
0
chima
Asked:
chima
  • 11
  • 8
  • 2
  • +1
1 Solution
 
Chase707Commented:
you can do this by using the strcpy C library function.

char* s4 = new char[str1.length() + 1];

strcpy(s4, str1.c_str()); // now you have a copy of the data in s4

Chase707

0
 
chimaAuthor Commented:
Chase707, the method doesn't quit like it; error C2082: redefinition of formal parameter 's4'

If I comment out the char* s4 = new char[str1.length() + 1]; statement, it like it, but does not execute.
0
 
chimaAuthor Commented:
Chase707, I should say that I am passing s4 by pointer.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
chimaAuthor Commented:
Chase707, figured it out; char* s4 = new char[str1.length() + 1]; does not need the char*
thanks, I'll grant your points once I'm very sure (short while.) thanks once again.
0
 
ExceterCommented:
>> char* s4 = new char[str1.length() + 1]; does not need the char*

Yes it does. Whether s4 was declared previously or not is irrelevant, s4 is a char* regardless. :-)

Exceter
0
 
Chase707Commented:
ok, here are some (Bad) examples for you to illustrate the problem with memory allocation and char*.


void charsFromStdString(string strIn, char* pOut)
{
    assert (pOut != NULL); // try to catch null pointers...not too reliable
   
    strcpy(pOut, strIn.c_str());
}

int main()
{
    std::string str("foobar")
    char* szChar = 0; // should allocate here, but forgot
   
    charsFromStdString(str, szChar); // will crash

    cout << szChar;

    delete [] szChar;
    return 0;
};

The problem here is that charsFromStdString doesn't know anything about the pOut parameter, except it's type, and has to assume that enough memory has been allocated to performer the copy operation.   Suppose you accidentily forget to allocate enough memory memory before calling the function?  Then you will crash your program.

So, you could try the reverse, that is, rely on charsFromStdString to allocate the memory:

void charsFromStdString(string strIn, char* pOut)
{
    pOut = new char[strIn.length() + 1]; // allocate here

    strcpy(pOut, strIn.c_str());
}

int main()
{
    std::string str("foobar")
    char* szChar = new char[strIn.length() + 1]; // shouldn't allocate here, but did

    charsFromStdString(str, szChar);

    cout << szChar;

    delete [] szChar; // now we still have to delete
    return 0;
};


What is the problem with this solution?  Suppose you forget exactly how charsFromStdString handles the pointer, does it allocate memory, or not?

So you allocate memory for the parameter before calling the function, and then then function also allocates memory.  now you have a memory leak.
Also, with this example, possibly you don't know the lifetime of the memory.

In complicated programs you can't be looking though every function to remember who is allocating what memory.  so, you have to develop a standard way.  my standard is to use the first method in most cases, because I believe that client functions should control their own memory.  Also it doesn't make sense for a copy operation to allocate memory.  There are cases though where it does make sense, such as when using COM, which is a whole different story altogether.  frankly, I rarely use char* at all.


the best solution is this:

std::string str1 = "hello";
std::string str2 = "foobar;

str1 = str2;

much nicer.  In your other post you are reading in data from cin into char* -- the example code I posted completly eliminated your dependence on char*, except when using cin.getline -- so it is possible to drop char* altogether in many cases.
0
 
chimaAuthor Commented:
Chase707, as I mentioned, it does work.  Now I have another problem associated with s4.  I'm passing s4 by pointer. I equate a string content to s4 (problem you solved), then I return s4 by, return *s4;.  The method is;
char& Str::append(char* s4, char* s1){
return *s4;
}
When I print this char* array from main(), it is not equal to s4.  Why?
0
 
Chase707Commented:
>>Chase707, as I mentioned, it does work

that's not really the point.  there are a lot of things you can do that work, but are incredibly wrong, cause leaks, bugs, etc.  I have a feeling that you are doing exactly what I described in method 2 above, but I may be wrong.

Anyway, for your answer, the reason you have a problem is because your return type (char&) is a reference to a char, not a char* -- so the only thing that will get printed is the first character of your char array.

if you want to return a char*, return a char*:

char* Str::append(char* s4, char* s1)
{
   // append to s4

   return s4;
}

better yet, assuming you allocated szTarget before the function call:

char* Str::append(char* szTarget, char* szSource)
{
    return strcat(szTarget, szSource);
}

0
 
chimaAuthor Commented:
Chase707, When I'm tired, I make silly mistakes.  I made the correction you caught and tried your last suggestion.  The results are the same.  The string is not being passed.
I wonder if there is a solution?  What do you think Exceter?
0
 
Chase707Commented:
>>The results are the same.  The string is not being passed.

Something must be wrong with the string you are passing in.

Post your code for calling the function, the code for append, and the code for outputing your results.

Chase707
0
 
chimaAuthor Commented:
Chase707, I'll post it for a short while then I'll try to remove it.  I'm bumpping up the points.  thanks
#include <cstring>
#include <iostream>
#include <string>

#define buf 50
#define NULL 0

using namespace std;

class CDyStr{
private:

public:
     char *pS1;
    char *pS2;
     char *pS3;
     char *pNewS4;

     

     CDyStr();
     ~CDyStr();

     char* append(char*, char*);
     char* concatenate(char*, char*, char*);
     char* replace(char*, char*);

};//CDyStr

     CDyStr::CDyStr(){
          pS1=     new char[buf]= NULL;
          pS2=     new char[buf]= NULL;
          pS3=     new char[buf]= NULL;
          pNewS4= new char[(2*buf)]= NULL;
         
     }

     CDyStr::~CDyStr(){
     delete pS1;
     delete pS2;
     delete pS3;
     delete pNewS4;
     }

//append: S1 <- S1 + "Ca va, mon ami"
//  S1: "Bon Jour Ca va, mon ami"
char* CDyStr::append(char* s_to_append_to, char* s_to_append){

     //cout<< '\t'<< s_to_append_to << endl;

     std::string str1(s_to_append_to);
     std::string str2(s_to_append);

     str1.append(str2);

     //cout<< str2 << endl;
     
     s_to_append_to = new char[str1.length() + 1];

     strcpy(s_to_append_to, str1.c_str());
     
     //cout<< '\t'<< s_to_append << endl;
     cout<< s_to_append_to << endl;

     return s_to_append_to;
};

//concatenate: S3 <- S1 + S2
//     S1, S2 remain unchanged
//     S3 is a new string made from the strings S1 and S2
char* CDyStr::concatenate(char* s1_to_concat, char* s2_to_concat,char* s4_s_result){
     
     string str1(s1_to_concat);
     string str2(s2_to_concat);
     string str3(s4_s_result);

     str3=str1+str2;

     //cout<< str3 << endl;

     s4_s_result = new char[str3.length() + 1];

     strcpy(s4_s_result, str3.c_str());

     cout<< s4_s_result << endl;

     return s4_s_result;
};

//replace: S1 <-"Ca va, mon ami"
//  S1: "Ca va, mon ami"
//  S1 is a new string--the old S1 is gone.
char* CDyStr::replace(char* s_to_rep_by, char* s_rep){

     string str1(s_to_rep_by);
     string str2(s_rep);

     str1=str2;

     //cout<< str1 << endl;

     s_to_rep_by = new char[str1.length() + 1];

     strcpy(s_to_rep_by, str1.c_str());

     cout<< s_to_rep_by << endl;

     return s_to_rep_by;
};

int main(){

     
     char *pS1={"Bon Jour "};
     
     char *pS2={"mon petit frere "};

     char *pS3={"Bon Jour mon petit frere "};

     char *pNewS4={"Emty String"};

     CDyStr TestStr;

     TestStr.append(pS1,pS2);
     TestStr.concatenate(pS1,pS2,pNewS4);
     TestStr.replace(pS1,pS3);

     cout<<endl<<endl;
     cout<< '\t'<< "The append() method is appending two strings with"<<endl<<
          '\t'<<"the result in first string."<<     endl;
     cout<< '\t'<< pS1 << " AND " << pS2<< endl;
     cout<< '\t'<< TestStr.pS1                  << endl << endl;
     
     cout<<endl<<endl;
     cout<<'\t'<<"The concatenate() method concatenats two strings with"<<endl<<
          '\t'<<"the result in another string."<<     endl;
     cout<<'\t'<<pS1 << " AND " << pS2 << endl;      
     cout<<'\t' <<"Result of the concatenation is in: " << endl <<
          '\t' << TestStr.pNewS4 << endl;

     cout<<endl<<endl;
     cout<<'\t'<<"The replace() method replaces the first strings with"<<
          " the second string"<<endl;
     cout<<'\t'<<pS1 << " AND " << pS3 << endl;      
     cout<<'\t' << "Result of the replacement is in: " << endl <<
          '\t'<< TestStr.pS1 << endl;
     cout<<endl<<endl;

     return 0;
}
0
 
Chase707Commented:
chima, I have your code.  I don't know why you want to delete it -- it is the weekend, so others may not get to look at the question until next monday.  

Anyway, it is late, and I'll post a detailed suggestion for you tommorrow.  the hint for now is that you are not assigning anything to the data members of your CDyStr.


0
 
chimaAuthor Commented:
Chase707, I threw in the TestStr. to the cout<< statement, which is not correct.  I was just seeing what would happen.
0
 
chimaAuthor Commented:
Chase707, Yeah I think you are right.  Over night I thought of this and realized that I did not use an initialization list,i.e., : to properly assign the parameter list.  I'm albout to change that.  I will look forward to your response.
I was also thinking that the string manipulation that we did in the method could be a solution to my other question posted, i.e., the
vecStringBuf.push_back(std::string(szInput)).  I'll try that as well.
0
 
Chase707Commented:
OK, First, a description of memory allocation for char*, maybe to clear things up a little for you.


char* needs to be initialized, or allocated with the proper number of bytes before you use it.

examples:
char* psz = "my string";   // the compiler automatically allocates 10 bytes (1+length of string)
char* psz2 = new char[10]; // allocate a 9 letter char*, you need to explicitly delete [] the memory
char sz3[10];              // allocate a 9 letter char array, compiler will handle memory cleanup

psz, psz2, and sz3 are only pointers to a memory addresses, and that memory address is the location of the first char 'm' in this case.

if you want try an experiment:

char* psz = "my string";

cout << psz << endl;

psz ++; // increment one memory location

cout << psz << endl;

your output now should be:

my string
y string




ok, so now your problem, why isn't append working.

doing this:

char* pS1 = {"Bon Jour "};

then, in append:

s_to_append_to = new char[str1.length() + 1];

is very bad.  why?  because first you assign pS1 to a memory location with 10 bytes allocated.  Imagine for example, that pS1 points at memory location 150, so memory locations 150, 151...159 are reserved only for that char array.

now you pass the memory address 150 (pS1) into append, so the parameter s_to_append_to now points at memory location 150.

then you call new, thus assigning a new memory address to s_to_append_to, for example address 200 -- pS1 still points to memory location 150.

It is also a memory leak, because you are calling new and not deleting the memory associated with it.


So, how to do what you want?   use a double pointer:


if your header:
class CDyString
{

...
    char* append(char**, char*);
...
}


in your .cpp:


char* CDyStr::append(char** s_to_append_to, char* s_to_append)
{
     
    std::string str1(*s_to_append_to);
    std::string str2(s_to_append);
     
    str1.append(str2);

    char* szNew = new char[str1.length() + 1];  // create the memory
     
    strcpy(szNew, str1.c_str()); // copy the memory
   
     *s_to_append_to = szNew;  // now assign the szNew pointer to s_to_append_to pointer

    return *s_to_append_to;
};


main:

...
    char *pS1 = "Bon Jour ";
    char *pS2 = "mon petit frere ";
    char *pSaveTmpPointer = pS1;   // temp pointer so we don't lose the location of "Bon Jour"
     
    cout << pS1 << " + " << pS2 << " = ";
     
    TestStr.append(&pS1,pS2);

    cout << pS1 << endl << endl;

    delete [] pS1; // make sure to delete the memory assigned.

    pS1 = pSaveTmpPointer; // restore pS1 back to original

    cout << pS1 << end;

...


I have simplified the example to only the parts you are worried about now, i.e. append

let me know if that example is clear, if not, ask and i'll try and explain some part of it.
0
 
Chase707Commented:
your member variables of CDyStr have no use in this situation.  Explain in further detail what your objective is and maybe I can figure out how you should use them.
0
 
chimaAuthor Commented:
Chase707, thanks for the detailed explanation..worth 200.
I was realizing that my member variables were not "being used."  I'll delete them.  I'll try to implement and full understand what you wrote.  I've never used char**, so it will be a learning process here.
0
 
tuBrodyCommented:
Is this what you are looking for?

char *s1 = ...
...
string str1(s1);
....
s4 = str1.c_str();

0
 
tuBrodyCommented:
or you could just strcpy the value returned by c_str:

char *s1 = ...
...
string str1(s1);
....

char s4 = new char[ str1.size()+1 ];
//added 1 for null termination char

strcpy (s4, str1.c_str());

....
0
 
chimaAuthor Commented:
Chase707, It is working now, thanks.  A couple of final questions.
If within the method this statement;
char* new_s_to_append_to = new char[str1.length() + 1];
creates new memory.  Would I not have to delete these memory.  I tired within the method and it did not like it.
Or is it because it is within that scope that it is automatically deleted?
If I do need to deleted...where, in the destructor?

The other question;  I commented out these:
     //char *pSaveTmpPointer = pS1;  
        //pS1 = pSaveTmpPointer;
and it seems to function correctly.  I can't see where the pointer is changed.  I would understand restoring the pointer if it had been changed,i.e., pS1++  ?

I think that take care of this initial question.  I want to issue your points now, but will it close the question, thereby disallowing you to answer these final questions.  Therefore I'll wait.  You have surely earned an A+++++
0
 
Chase707Commented:
>>Would I not have to delete these memory.
>>I tired within the method and it did not like it.
>>Or is it because it is within that scope that it is automatically deleted?

You are almost correct. when you delete it inside of the function, you are doing precisely that, deleting the memory.  then your pointer to that memory outside of the function become invalid.

Therefore, you need to make sure you delete the memory after using your pointers outside of the function.

I hope that's clear.  I think you will learn better methods in the future, but it is too much info to describe for one question.


//char *pSaveTmpPointer = pS1;  
       //pS1 = pSaveTmpPointer;
and it seems to function correctly.  I can't see where the pointer is changed.

It does work correctly, but without that, you actually loose your initial pointer to "Bon Jour " that you created at the beginning.  This is a problem if you every want to use that initial string again.   It could be considered a memory leak as well, but in this case it isn't because the memory for string literals (char* sz = "my string") are guaranteed to exist for the entire life of the program -- that is, they have global scope.  The memory will be automatically deleted at program termination.  If you were not using a string literal, but used new[] to allocate your memory, then you would have a leak that could possibly eat up your system memory, and never free it.

Chase707
0
 
chimaAuthor Commented:
Very well done.  Interesting that one can create such an entranglement while tying to keep it simple.  I appreciate your help.  Please keep checking I'm sure I'll have other questions. Kudos to you!
0

Featured Post

Upgrade your Question Security!

Your question, your audience. Choose who sees your identity—and your question—with question security.

  • 11
  • 8
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now