0

guys I was trying to put several different strings like these:

cap to cat card two too up boat boot 

into a char* array like this:

char* result[9] 

and after assigning every one of those strings into the array with a for loop, I found that all the elements in the array is the same, which is "boot".

My code and result are down here:

#include<iostream> #include<algorithm> #include<cstring> using namespace std; int main() { char* result[9]; for(int counter=0;counter<9;counter++) { string temp; getline(cin,temp); result[counter]=(char*) temp.c_str(); cout<<result[counter]<<endl;//correct } cout<<endl; cout<<endl; for(int counter=0;counter<9;counter++) cout<<result[counter]<<endl;//false } 

This line works well,

 cout<<result[counter]<<endl;//correct 

and it prints all the different words like:

cap to cat card two too up boat boot 

but somehow, this line

 cout<<result[counter]<<endl;//false 

it only prints "boot" nine times. I really can't see the reason here and I am hoping you guys can give me a hand, thx!

1
  • 2
    Your code has a deeper problem. You are assigning the address of a local variable that outside the first loop will be invalid. Commented Apr 5, 2019 at 9:35

4 Answers 4

3
{ string temp; getline(cin,temp); result[counter]=(char*) temp.c_str(); /* 1 */ cout<<result[counter]<<endl;//correct } /* 2 */ 

In the line marked 1, you're storing a pointer to the underlying string data of temp in result[counter]. None of the string contents are copied; you're just storing the address of the existing data in temp. (By the way, what is the (char*) cast for? .c_str() already returns a pointer to char.)

In the line marked 2, temp is destroyed (it was a local variable in this block). Now result[counter] contains an invalid pointer: The object it was pointing to doesn't exist anymore.

Any attempt to use the contents of result after this result in undefined behavior.

One way you could fix this is to use an array of strings instead of an array of pointers:

string result[9]; for(int counter=0;counter<9;counter++) { getline(cin,result[counter]); cout<<result[counter]<<'\n'; } 

(I've also removed endl because there is no need to explicitly flush the stream after every single string.)

This also simplifies the code a bit because you no longer need a temp variable: You can just getline directly into the array.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the reply! Though I still have a question: according to what you have said, the local variable should be destroyed after the for loop, however when I print out the result array after the for loop, it gives nine 'boot' which is the last word I input, do you have any idea why?
And I used (char*) cast because by default c_str() function returns const char*.
@admin822 It's undefined behavior. It can do whatever it wants. Also, why cast away const? You could have just changed the type of result to include const.
1

Better yet use std::vector<string>

std::vector<std::string> result; for(int counter=0;counter<9;counter++) { std::string temp; std::getline(std::cin, temp); result.push_back(temp); } 

If you want to use pointers, you need to copy the contents of str.c_str() as it is a temp that is destroyed after each iteration.

1 Comment

Appreciate the reply. But I actually know how to save several input strings and I have solved this problem with a list<string>. I am just curious about why my original code would print the last word 'boot' nine times.
0

In following loop you are declaring temp string and using it again and again. so in each iteration of the loop, same pointer is being edited. hence the last value stays and rest are overwritten.

for(int counter=0;counter<9;counter++) { string temp; getline(cin,temp); result[counter]=(char*) temp.c_str(); cout<<result[counter]<<endl;//correct } 

Instead declare your temp string outside as a string array with capacity of 9.

#include<iostream> #include<algorithm> #include<cstring> using namespace std; int main() { char* result[9]; string temp[9]; for(int counter=0;counter<9;counter++) { getline(cin,temp[counter]); result[counter]=(char*) temp[counter].c_str(); cout<<result[counter]<<endl;//correct } cout<<endl; cout<<endl; for(int counter=0;counter<9;counter++) cout<<result[counter]<<endl;//false } 

Comments

0

There is a problem with your code and specifically with this line:

result[counter]=(char*) temp.c_str(); 

Since temp lives within the for loop and c_str() returns an address that will be invalid once temp is destructed, your code suffers from UB. The address is invalid because c_str():

Returns a pointer to the underlying array serving as character storage.

Once temp is out of scope, that underlying array is gone, but you now have a reference to it outside its scope!

You should allocate new memory for each of the string in result maybe using strdup as in the following:

#include<iostream> #include<algorithm> #include<cstring> using namespace std; int main() { char* result[9]; for(int counter=0;counter<9;counter++) { string temp; getline(cin,temp); result[counter]=strdup(temp.c_str()); //now it is correct! cout<<result[counter]<<endl; } cout<<endl; cout<<endl; for(int counter=0;counter<9;counter++) cout<<result[counter]<<endl; } 

Do not forget that strdup will allocate memory that needs to be deallocated manually.

1 Comment

Yeah, but now you're leaking memory and strdup is a non-standard function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.