Confusion with duplication of string in C++ language - c++

Everytime I encounter the situation dealing with c string, I'm very confused.
why are those two prints have same result?
In my understaning, first function assigns the address of string at text variable. which seems proper to me. But the second function assigns the address at where text variable points to. what happened here?
#include <iostream>
#include <cstring>
void getText(char** text) {
*text = strdup("AAAAA");
}
void getText2(char* text) {
text = strdup("AAAAA");
}
int main()
{
char* text;
getText(&text);
std::cout << text << std::endl; // prints "AAAAA"
getText2(text);
std::cout << text << std::endl; // prints "AAAAA"
}

This function
void getText2(char* text) {
text = strdup("AAAAA");
}
has a memory leak.
Function parameters are function local variables.
You can imagine the definition of the function getText2 and its call the following way. I renamed the function parameter that it would be more clear.
getText2(text);
//...
void getText2( /*char* parm_text */) {
char *parm_text = text;
parm_text = strdup("AAAAA");
}
The local variable that is the parameter parm_text will be destroyed after exiting the function. However the allocated memory in this statement
parm_text = strdup("AAAAA");
is not freed.
On the other hand the argument itself was not changed. The function used the value stored in the argument that was assigned to the local variable.
You could declare the parameter as reference to the argument. For example
void getText2(char* &text) {
^^^^^
text = strdup("AAAAA");
}
In this case it is the argument itself that is changed in the function.
As for the function
void getText(char** text) {
*text = strdup("AAAAA");
}
then the argument is passed indirectly by using a pointer to the argument. So inside the function the value of the argument is changed.

In the first case, you passed a pointer to your local pointer, you dereference that pointer and make it point to the value returned by strdup(), you are modifying the address the original pointer points to.
In the second one, you pass the poiner itself, you cannot alter it inside the function because even if the two pointers point to the same memory initially, they are stored in different places, so altering the address of one doesn't affect the other.
If you alter the data the pointer points to, and not the address in getText2() then it will change, like
text[0] = 'B';
text[1] = 'B';
text[2] = 'B';
text[3] = 'B';
text[4] = 'B';
You should also call free() after you use the pointer returned by strdup() or it will be a memory leak.
Finally, using pointers in c++ is currently considered bad practice unless you are a library programmer, which I don't think is the case. Instead, use std::string and all the c++ concepts (like pass by reference which doesn't exist in c) that will allow you to write modern c++ programs.
Passing by reference in c++ is possible
void getText(std::string &text)
{
text = "AAAAAA";
}
void getText2(std::string &text)
{
text = "BBBBBB";
}
int main()
{
std::string text;
getText(text);
std::cout << text << std::endl;
getText2(text);
std::cout << text << std::endl;
return 0;
}
There you go, no memory leaks, it works as expected, and it's modern c++.

Related

How can you change the value of a string pointer that is passed to a function in C++?

I need to change the value of a std::string using a function.
The function must be void, and the parameter must be a pointer to a string as shown.
#include <iostream>
void changeToBanana(std::string *s) {
std::string strGet = "banana";
std::string strVal = strGet;
s = &strVal;
}
int main() {
std::cout << "Hello, World!" << std::endl;
std::string strInit = "apple";
std::string* strPtr;
strPtr = &strInit;
changeToBanana(strPtr);
std::cout << *strPtr << std::endl;
return 0;
}
I would like the resulting print to say "banana"
Other answers involve changing parameter.
I have tried assigning the string using a for loop, and going element by element, but that did not work. The value remained the same.
The function must be void, and the parameter must be a pointer to a string as shown.
With this requirements you cannot change the value of the pointer that is passed to the function, because it is passed by value.
Don't confuse the pointer with what it points to. Parameters are passed by value (unless you pass them by reference). A copy is made and any changes you make to s in the function do not apply to the pointer in main.
However, you can change the string pointed to by the pointer (because s points to the same string as the pointer in main):
void changeToBanana(std::string *s) {
std::string str = "banana";
*s = str;
}
However, this is not idiomatic C++. You should rather pass a a reference void changeToBanana(std::string& s) or return the string std::string returnBanana().
void changeToBanana(std::string *s) {
std::string strGet = "banana";
std::string strVal = strGet;
// the following line doesn't do anything
// useful, explanation below
s = &strVal;
}
s = &strVal assigns the address of the strVal to s. Then the function ends and any modifications made to s are "forgotton", becase s is a local variable of changeToBanana.
So calling changeToBanana(&foo) does nothing.
You either want this:
void changeToBanana(std::string *s) {
*s = "banana";
}
...
std::string strInit = "apple";
changeToBanana(&strInit);
or this (preferred because you don't need pointers):
void changeToBanana(std::string & s) {
s = "banana";
}
...
std::string strInit = "apple";
changeToBanana(strInit);

Confusing behavior of C++ string returns and c_str() casts [duplicate]

This question already has answers here:
Why does calling std::string.c_str() on a function that returns a string not work?
(3 answers)
Closed 2 years ago.
I am new to C++ programming (work with Java mostly), and this behavior of C++ classes, member strings and string conversions to const char* with c_str() is confusing me.
I have a header, a class and main function as follows:
sample.h
class Sample
{
private:
int id;
std::string text;
public:
Sample(int id);
void setId(int id);
int getId();
void setText(std::string txt);
std::string getText();
void loadText();
~Sample();
}
sample.cpp
Sample::Sample(int id)
{
this->id = id;
}
void Sample::setId(int id)
{
this->id = id;
}
int Sample::getId()
{
return this->id;
}
void Sample::setText(std::string txt)
{
this->text = txt;
}
std::string Sample::getText()
{
return this->text;
}
void Sample::loadText()
{
this->text = "Loaded";
}
Sample::~Sample()
{
std::cout << "Destructor is called." << std::endl;
}
main.cpp
void main()
{
int id = 1;
Sample* sample = new Sample(id);
// Case: 1 - If I do this, it does not work. Prints gibberish.
sample->loadText();
const char* text = sample->getText().c_str();
std::cout << text << std::endl;
// Case: 2 - Otherwise, this works.
sample->loadText();
std::cout << sample->getText().c_str() << std::endl;
// Case: 3 - Or, this works
sample->loadText();
std::string txtCpy = sample->getText();
const char* text = textCpy.c_str();
std::cout << text << std::endl;
}
All three cases are done one at a time.
Case 3 does satisfy my use case (which is, passing the string to a C library that expects a const char*. But, I can't figure out the difference between Case: 1 and Case: 3? If we are returning the string by value, how does copying it to an intermediate variable make it kosher for the run-time?
The result of c_str() is only valid while the string you called it on still exists. In case 3, txtCpy still exists at the point you are writing cout << text. But in Case 1, the string was the return value of sample->getText which is temporary and stop existing at the end of that line .
This issue always will exist if you take pointers or references to other objects. A naked pointer or reference has its own lifetime which may differ from the lifetime of the targeted object. This is unlike Java where object references all participate in the lifetime of the object.
As such, you always need to think about object lifetimes when using these features, and it's commonly recommended to instead use higher level features or other code styles that do not permit lifetime management errors.
You could consider adding a member function to Sample which gets a const char * pointing at the original string (although this is a wee violation of encapsulation, and still has a similar class of problem if you hold onto the pointer and then modify the underlying string). Better would be to just avoid working with the naked pointers entirely.
In this code snippet
const char* text = sample->getText().c_str();
std::cout << text << std::endl;
the variable text is assigned by a pointer (c_str()) of a temporary object returned from the member function getText. After this statement the temporary object will nit be alive, So the variable text has an invalid pointer,
The code snippet could be valid if the member function returned reference to the data member text like for example
const std::string & Sample::getText() const
{
return this->text;
}
Pay attention to that this declaration of main
void main()
is not a standard declaration.
The standard declaration of main without parameters is
int main()

Design a method or function which returns a valid string

Based on the idea of this entry Is it a good idea to return “ const char * ” from a function?
I thought to extend this with another question I have.
Consider the following code:
#include <string>
#include <cstdio>
const char * GetSomeString()
{
std::string somestlstring;
somestlstring = "Hello World!";
return somestlstring.c_str();
}
int main()
{
const char * tmp = GetSomeString();
printf("%s\n", tmp);
return 0;
}
If I build it with
g++ source.cpp -o executable
and execute that, I get strange symbols displayed. This is because somestlstring is destroyed through the callstack and the pointer you keep after returning became invalid.
My question is: how should I design a method or function that does not have such behaviour without actually declaring additional global variables or potential member functions?
You should drop the whole C mindset and start writing C++:
#include <string>
#include <iostream>
std::string GetSomeString()
{
std::string somestlstring;
somestlstring = "Hello World!";
return somestlstring;
}
int main()
{
std::string tmp = GetSomeString();
std::cout << tmp << std::endl;
return 0;
}
One obvious solution is to make the return type std::string.
how should I design a method or function that does not have such beahviour without actually declaring additional global variables or potential member functions?
Not at all. If you return a const char *, your function is kind of telling the caller "here you have a C string to use, but it stays mine" *), and this implies the caller doesn't have to bother releasing the resources, for example. So you can do this from an instance method (returning a pointer to a field) or you can have a function return a pointer to some static buffer (global variable).
If you want to return a dynamically allocated C string from a function, you must return char * instead and the caller has to free() it when done using it.
That all said, in C++ this doesn't make much sense, except when somehow interfacing with C code. If you want to write C++ code, go with nvoigt's answer.
*) this is thinking in terms of ownership, which is very helpful dealing with manually managed resources. The owner of something is responsible for appropriate cleanup. You can only return a const raw pointer if you don't transfer ownership of the object to the caller.
You are currently referencing the memory of a local std::string object which is destroyed when the object goes out of scope (when returning from the function)
if you really want to return a const char *:
you have to make your std::string static (but only 1 value is shared by your application)
or you have to duplicate the string memory (but you need to free it or you get memory leaks, like happened a lot with the old str() method of the old strstream object, which was later converted to std::string)
But as others said, better stick to C++ std::string (or const reference) as a return value and take c_str() of that returned string when needed for C-style interfaces.
std::string tmp = GetSomeString();
FILE *f = fopen(tmp.c_str(),"r");
The local string variable in the GetSomeString() function will get out of scope after you returned from the funtion. You will be printing random stuff that is in the memory position where the string was before. Try this:
#include <string>
#include <cstdio>
void GetSomeString(std::string& str)
{
str = "Hello World!";
}
int main()
{
std::string str;
GetSomeString(str);
std::cout << str << std::endl;
return 0;
}

Create struct object in a function and pass its pointer

I am trying to pass in a empty struct pointer into a function called "initialize" as an output parameter and then after the function finishes I could retrieve the object pointed by the struct pointer. Some unexpected behaviors occur and I don't quite understand.
Below is my code:
static void initialize(complex_struct*& infoPtr)
{
complex_struct myInfo;
infoPtr = &myInfo;
// some other codes that modify the contents of myInfo
infoPtr->input_components = 3;
}
static void myfunction()
{
complex_struct* infoPtr = nullptr;
initialize(infoPtr);
std::cout << infoPtr->input_components << std::endl;
}
The output of this is an arbitrary large integer number. But I was expecting an integer 3 is printed.
Restrictions:
I cannot modify complex_struct; it is a third_party struct that needs to be used.
Also, the reason why I need initialize() to be a separate function is that I am doing performance measurement on the memory allocation of complex_struct. So moving the first line of code in initialize() to myfunction() is not an ideal solution.
You are trying to use the pointer to local variable outside of it's scope funciton. In your example, myInfo instance inside initialize() will be deleted after you exit the function, and the address you remembered will be pointing to random garbage memory. You should never use pointers to local variables outside of their scopes.
How to fix the issue? The easiest way would be to ditch the pointer here, and instead pass your struct by non-const reference. Code would look like following:
void initialize(complex_struct& info)
{
// some other codes that modify the contents of myInfo
info.input_components = 3;
}
void myfunction()
{
complex_struct info;
initialize(info);
std::cout << info.input_components << std::endl;
}
There is one subtle flaw in the suggested code: effectively info is initialized twice. First time when it's instance is created (complex_struct info) and the second time inside initialize() function. It would not have any noticeable effect in this example (info is allocated on the stack, and I do not think it has any non-trivial constructor) but might be of bigger problem in other setting. The best way to initialize it in this case would be to return the struct from the initialzer function, and rely on copy-elision to optimize away all the copies. Illustration code:
complex_struct initialize()
{
complex_struct info;
// some other codes that modify the contents of myInfo
info.input_components = 3;
return info;
}
void myfunction()
{
complex_struct info = initialize();
std::cout << info.input_components << std::endl;
}
You are returning a pointer to an object in the stack frame. That object gets deleted when the function returns. You have a dangling pointer in myfunction.
Ways to solve the problem:
Allocate memory from heap
static void initialize(complex_struct*& infoPtr)
{
infoPtr = new complex_struct ;
infoPtr->input_components = 3;
}
Make sure to deallocate the memory in the calling function.
Use an object, instead of a pointer
static void initialize(complex_struct& info)
{
info.input_components = 3;
}
and change its usage:
static void myfunction()
{
complex_struct info;
initialize(info);
std::cout << info.input_components << std::endl;
}

C++ char * pointer passing to a function and deleting

I have a the following code:
#include <iostream>
using namespace std;
void func(char * aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] aString;
aString = tmpStr;
}
int main()
{
char * str= new char[100];
cin.getline(str,100);
cout<< str <<endl;
func(str);
cout<< str <<endl;
return 0;
}
Why the second cout does not print the second input string? How can I change this code to work it?
As GregS has said, the simplistic answer is to declare your function using a reference:
void func(char *&aString)
However it is not really the best solution. In C++ you generally avoid simple arrays and use containers.
#include <iostream>
#include <string>
void func(std::string &s)
{
std::getline(std::cin, s);
}
int main()
{
std::string str;
func(str);
std::cout << str << std::endl;
return 0;
}
Because the second cout will print what is pointed by str. And str, the pointer, in your main function will have the same value before and after the call to func.
Indeed, in the func function, you are changing the value of the aString variable. But this is another variable than str in main.
If you want the value of str to be changed, you have to pass it to func by reference or by pointer. (Note that what you write, is to pass the characters by pointer. I mean you have to pass the pointer by pointer: void func(char **str_ptr), or by reference void func(char *&str_ref))
If you're really doing C++, you should use std::string instead of the old C strings.
An example of passing the pointer by pointer:
func(char ** aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] *aString;
*aString = tmpStr;
}
Plus you should call it like this: func(&str);
When func() is called from main() the value of str pointer is passed to the function (this is done by copying it's value to the stack)
The value that was stored on stack when calling func() becomes a local variable aString within func(). You can modify this value but as soon as func() returns all of it's local variables will be discarded. Value of aString won't be copied back to str.
For your code to work you have to either:
Use the buffer pointed to by aString to read data: cin.getline(aString ,100);
or
Pass pointer to pointer: void func(char **aString)
Change func to
void func(char * aString)
{
cin.getline(aString,100);
}
and it works, at least it did for me.
The pointer is passed by value. Yes, you can change the content of what that pointer points to, but the old address itself is preserved when you exit the function. Hence, "aString=tmpStr"; becomes useless and "char * tmpStr= new char[100];" creates a memory leak. You need to pass the pointer by reference:
void func(char*& aString)
{
char * tmpStr= new char[100];
cin.getline(tmpStr,100);
delete [] aString;
aString = tmpStr;
}
If your aim is to actually read a line from the keyboard, do this:
std::string foo;
std::getline(std::cin, foo);
Otherwise, when you pass a pointer to a function, the pointer is passed by value. This means you cannot change the pointer itself from within the function, but you can change the object it points to. In C++ you could do this as follows:
void bar(std::string & s) {
std::getline(std::cin, s);
}
// in calling code
std::string foo;
bar(foo);
This passes a reference to the string to the function. The function can now change the contents of the string.
If you want to write a function that allocates some memory to store a result in, do it like this:
boost::shared_array<char> foo() {
boost::shared_array<char> result(new char[100]);
std::cin.getline(result.get(), 100);
return result;
}
assignment to the parameter aString within the function has no effect on str in main()
you might try
return aString
and in main
str = funct(str);
But in fact there's probably no reason to pass str into the function.
The line aString = tmpStr just changes the value of astring (i.e. an adress/pointer) to another value (i.e. another adress/pointer), but not the content of the momory pointed to by aString.
You could try to change the signature to:
void func(char ** aString)
And changing the last two lines of func to:
delete [] *aString;
*aString = tmpStr;
So the last line causes the program to change the adress stored in the memory pointed to by aString to the adress newly allocated (tmpStr). (I know, it's mind-boggling.)
And then call it via
func(&str);
You need to pass str as a reference.
#include <iostream>
void func(std::istream& is, std::string& aString)
{
std::getline(is, aString);
}
int main()
{
std::string str;
std::getline(std::cin, str);
if(std::cin)
std::cout<< str << '\n';
std::string str;
func(std::cin, str);
if(std::cin)
std::cout<< str << '\n';
return 0;
}
The pointer aString which you pass to func() indicates where (at which address) you can read and write the string str. When you then say aString = tempStr, you're replacing its original value (the address of the string pointed to by str) with a new value (the address of the string pointed to by tempStr). This will not cause str to point to the same place as tempStr.
Imagine I give you a piece of paper with my friend's home address it. Then you scratch it out and write the address of your brother (who lives in London) on it. If I then decide to visit my friend, I won't find myself traveling to London, even though you may have a piece of paper that says "Paul's friend: 123 London".
To get main to print out the string you entered in func(), you can either copy the input string to aString (you move your brother to my friend's house), or pass a pointer or reference to str (have me give you my address book, so you can change the entry for my friend to London). Either way, next time I visit "my friend's house", your brother will be there.