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

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.

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);

How do I inline a pointer in CPP?

Hey I'm new to c++ coming from java and I can't understand how to make this:
std::string some_string = "some text";
string* some_pointer = &some_string;
all in one line. Example of what I am thinking of:
void some_function(string* some_pointer);
some_function(get_pointer_of("test"));
This can be done but it would be a bad practice. You must handle the pointer inside the function or return the address again to handle it later.
An example
#include <string>
#include <iostream>
std::string* fun(std::string * str){
std::cout << *str;
*str = "ff";
return str;
}
int main(){
auto ptr = fun( new std::string{"ee"});//u have (new std::string{"ee"}) in one line
std::cout << "\n" << *ptr ;
delete ptr;
}
Demo
You cannot 1.
You can create temporary objects inline within expressions, but you cannot take their address directly. Conversely, you can take the address of a value inline, but you cannot do that with an rvalue.
1 ... in a simple way. And you should probably avoid doing it with a complex trick.

Confusion with duplication of string in C++ language

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++.

Passing char* to a function c++

So I've this issue I can't get fixed :-(
In my .h I've this:
protected:
char* _textPath_1;
FileReader* _reader_3;
in .cpp I've:
_reader_3 = new FileReader();
_textPath_1 = "foo";
_reader_3->openFile(_textPath_1);
And FileReader has this:
private:
char* fileName;
public:
signed int openFile(char* name);
but If I write this (just to test):
signed int FileReader::openFile(char* name) {
std::cout << name << std::endl;
fileName = name;
stream.open(fileName, std::ios::in);
if (!stream.is_open()) {
FileReader::printErrorOpeningFile(fileName);
stream.close();
return -1;
}
return 0;
}
fileName is a char * and I need that it gets the same value (foo) of name. I get an error, and I'm not even able to print name, it just print a blank line.. why?
EDIT: it's not working even using strcpy.. Actually inside the function I can't print the value of name, it's like it has been "deininitialized"
You need to allocate space for your text string _textPath_1.
Try this instead.
char myTextString[] = "foo";
_textPath_1 = myTextString;
This creates a local character array (a character string), which is initialized to "foo\0". It then copies that character string's address to your char pointer _textPath_1. As a LOCAL storage, it will only be valid in the local code block and will not be usable once your code has dropped out of its scope. If you need that string past the local code block, you will need to allocate it from heap memory (using new for instance) and remember to deallocate it after you are done with it.
You cannot use strcpy with your unallocated pointer because strcpy expects the destination char* to be pointing at a character array acting as your destination string buffer. As you haven't allocated any char space at all, it cannot copy "foo" into your _textPath_1, and that's why you get a runtime error when you try to strcpy it.
These and other fun with char* is why std::string was invented. No worries about allocating and deallocating space, having to use strcpy to copy its value, etc etc etc. Consider using std::string _textPath_1 in place of your char* _textPath_1.
You have to allocate _reader_3 before calling the function.
FileReader* _reader_3 = new FileReader;
I assume fileName is your member variable. Accessing pointers without initialization will result in unpredictable results
If you're really defining global variables in your header file:
char* _textPath_1;
FileReader* _reader_3;
Then you shouldn't be doing that. Global variables should be declared in header files, but defined in an implementation file.
This code works fine:
#include <iostream>
#include <fstream>
struct FileReader {
char* fileName;
std::fstream stream;
signed int FileReader::openFile(char* name) {
std::cout << name << std::endl;
fileName = name;
stream.open(fileName, std::ios::in);
if (!stream.is_open()) {
FileReader::printErrorOpeningFile(fileName);
stream.close();
return -1;
}
return 0;
}
void printErrorOpeningFile(char *) {}
};
int main() {
char* _textPath_1;
FileReader* _reader_3;
_reader_3 = new FileReader();
_textPath_1 = "foo";
_reader_3->openFile(_textPath_1);
delete _reader_3;
}

C++ management of strings allocated by a literal

Do I need to take care of memory allocation, scope and deletion of C++ strings allocated by a literal?
For example:
#include <string>
const char* func1() {
const char* s = "this is a literal string";
return s;
}
string func2() {
std::string s = "this is a literal string";
return s;
}
const char* func3() {
std::string s = "this is a literal string";
return s.c_str();
}
void func() {
const char* s1 = func1();
std::string s2 = func2();
const char* s3 = func3();
delete s1; //?
delete s3; //?
}
func2: I don't need to delete s2.
func3: Do I need to delete s3?
Is func1 correct? Is character memory content still available after it leaving func1's scope? If yes, should I delete it when I do not need it anymore?
func1() returns a pointer to a string literal. You must not delete string literals.
func2() (presumably, you omitted the std:: prefix) returns a std::string. It takes care of itself.
func3() returns a pointer to a string that's managed by a std::string object that's destroyed when the function exits. You must not touch that pointer after the function returns.
You would have to take care of the memory returned by this function:
const char* func4() {
char* s = new char[100];
// fill char array with a string
return s;
}
However, manual resource management is tricky. For starters, if a function returns a naked pointer, you don't know whether it points to one objects (char) or an array thereof and whether you need to delete it. You should avoid all that and just stick to std::string.
You have a different problem with s3, namely that the function func3() returns a pointer into an object that goes out of scope when the function returns. Don't.
To clarify: Your local string object within func3() will cease to exist on return of the function, so no need to delete. However, you still have a pointer to its internal buffer, which you return. You can't use that.
Very good and detailed past answer here, lest more confusion ensues: Is it more efficient to return a const reference
In func3 your string local is created by the compiler calling the implicit constructor string(const char*) initializing its internal buffer with a copy of the string literal. You then return a pointer to the internal buffer of the string which promptly goes out of scope and gets freed as soon as the function returns.
I snip the relevant code to each function and treatment of its return value, and comment below:
const char* func1() {
const char* s = "this is a literal string";
return s;
}
const char* s1 = func1();
delete s1; //?
You can't delete s1, as the string it points to does not live on the heap.
string func2() {
string s = "this is a literal string";
return s;
}
string s2 = func2();
This is fine. func2's s goes out of scope and cleans up. s2 will duplicate the string from s, and also clean itself up at the end of func.
const char* func3() {
string s = "this is a literal string";
return s.c_str();
}
const char* s3 = func3();
delete s3; //?
func3 returns a pointer to a string that has been freed. You will get a double free exception upon execution of delete s3.