Solved

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

Posted on 2003-03-07
Medium Priority
290 Views
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
Question by:chima
[X]
###### Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

• Help others & share knowledge
• Earn cash & points
• 11
• 8
• 2
• +1

LVL 4

Expert Comment

ID: 8091849
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

Author Comment

ID: 8092011
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

Author Comment

ID: 8092048
Chase707, I should say that I am passing s4 by pointer.
0

Author Comment

ID: 8092080
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

LVL 8

Expert Comment

ID: 8092159
>> 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

LVL 4

Expert Comment

ID: 8092278
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

Author Comment

ID: 8092311
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

LVL 4

Expert Comment

ID: 8092466
>>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

Author Comment

ID: 8092728
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

LVL 4

Expert Comment

ID: 8092761
>>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

Author Comment

ID: 8092857
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

LVL 4

Expert Comment

ID: 8092931
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

Author Comment

ID: 8092987
Chase707, I threw in the TestStr. to the cout<< statement, which is not correct.  I was just seeing what would happen.
0

Author Comment

ID: 8094113
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

LVL 4

Expert Comment

ID: 8094401
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;

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:

class CDyString
{

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

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

LVL 4

Expert Comment

ID: 8094407
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

Author Comment

ID: 8094485
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

Expert Comment

ID: 8094656
Is this what you are looking for?

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

0

Expert Comment

ID: 8094682
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

Author Comment

ID: 8094700
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

LVL 4

Accepted Solution

Chase707 earned 800 total points
ID: 8094790
>>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

Author Comment

ID: 8095212
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

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their waâ€¦
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a â€¦
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor anâ€¦
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
###### Suggested Courses
Course of the Month12 days, 17 hours left to enroll