I have a member function of a class which is defined below, say
int x(std::string &a, std::string &b) {
char *ptr = another_member.getStringMember().c_str() //I am storing the pointer
cout << ptr << endl;
a="hello";
cout << ptr << endl;
}
The output is
StringMember
Hello
Can you please explain why this happens ?? Thanks
Most likely because another_member.getStringMember and a are the same string.
In this case it is not actually legal to use ptr after the string has been modified with a="hello"; because mutating operations can make the previously obtained pointer invalid.
Just out of curiosity, do you call
x(another_member.getStringMember, fooBar);
?
c_str() returns internal pointer of string object which became invalid as soon as you modify the source string
You are not guaranteed that ptr is still usable after the a="hello" line (since it looks like they are the same string). In your case, since Hello was smaller, and the string wasn't being shared, it looks like it reused the space.
This is implementation specific behavior. It could have easily crashed.
The temp std::string from another_member.getStringElement() goes out of scope after the line is executed. Change
char *ptr = another_member.getStringMember().c_str();
to
std::string s = another_member.getStringMember();
const char *ptr = s.c_str();
Did you mean to do another_member.getStringElement().c_str() as against another_member.getStringElement.c_str().
Related
I'm just looking at the following code snippet:
#include<iostream>
#include<cstring>
using namespace std;
class String
{
private:
char *s;
int size;
public:
String(const char *str = NULL); // constructor
~String() { delete [] s; }// destructor
void print() { cout << s << endl; }
void change(const char *); // Function to change
};
String::String(const char *str)
{
size = strlen(str);
s = new char[size+1];
strcpy(s, str);
}
void String::change(const char *str)
{
delete [] s;
size = strlen(str);
s = s + 1;
s = new char[size+1];
strcpy(s, str);
}
int main()
{
String str1("StackOverFlow");
String str2 = str1;
str1.print();
str2.print();
str2.change("StackOverFlowChanged");
str1.print();
str2.print();
return 0;
}
I expect the output as:
StackOverflow,
StackOverflow,
StackOverflow,
StackOverflowChanged.
Before str2.change("StackOverFlowChanged") line, both str1 and str2's s point to the same memory location. However, in change method, since the pointer value changed, I except now str1 and str2's s point to the different locations and this is not the case. Can somebody explain why this is the case?
After calling str2.change, str1 no longer has a valid pointer. Since the two objects were sharing the same pointer, by deleting the array in one object, the other object now points to a deleted array. Attempting to access the array pointed to by str1 is undefined behavior, so str1.print() is invalid code.
Now, in this particular case, odds are good that the new char[] in str2.change just so happens to return a pointer to an address identical to the one that was just deleted. After all, the memory was just freed up, and no other allocations were made in the meantime. So while str1's pointer is still invalid, it just so happens to work out to pointing at a valid string by the time str1.print gets called.
But that's just happenstance; an implementation didn't have to do that. Undefined behavior is undefined, and you need to properly follow the Rule of 5. Or just use std::string.
The problem is that you called delete[] on the memory pointed by str1.
The runtime library is then allowed to reuse the same memory for the next allocation call and apparently this is what happened.
str1 didn't change the memory it pointed to, but the content changed.
Note that using a pointer to memory after it has been delete[]d is undefined behavior. So indeed anything can happen.
When you write classes that own heap allocated memory a lot of care should be taken about who owns the memory and when this memory is going to be released; in particular a lot of attention should go to copy constructor and assignment operator because the automatically generated code is rarely the correct one in case of memory owned using raw pointers.
No, str1 and str2 do not point to the same memory location, before str2.change("StackOverFlowChanged") line. str2 is in a different location but with the same value as of str1. You can verify this using -
cout << &str1 << '\t' << &str2 << endl;
It will show that they have different locations in memory.
I'm doing an exercise right now, so I will say right away that I don't want to use std::string to solve my problem.
I have a simple class that has a few fields and among them is char* text field that can be assigned and re-written or re-allocated.
class MyClass
{
private:
char* name;
...
public:
operator char*() const { return name;}
}
What I'm trying to do is make an implicit conversion to char* so that I can do this in my program:
Myclass s = "Hello" //allocates 6 bytes and pust a 0-terminated "Hello/0" line into "name"
char* c = s
s = "Hello World" //re-allocates memory, frees previous memory
cout << "Str: " << s << " Char: " << c;
Obviously, just as I noticed even before testing, when the re-allocation of "name" happens and the memory is freed - "c" now points to garbage.
So this code is no-go and I fully understand why.
I could allocate new memory and return a pointer to it, I guess:
operator char*() const
{
int length = strlen(name)+1;
char* ptr = new char[length]
std::copy(name, name+length, ptr);
return ptr;
}
but in this case, if I later re-assign "c" to something else - then the memory will never be freed, right? If I do this:
c = "Bye";
then basically the memory that I copied "name" to will still remain allocated and leaK?
The question is: how to make this right? Should I even worry about this, or do I simply assume that the user who re-assigns "c" should take care of clearing the memory first?
I will repeat that my goal is to do this through memory manipulation and pointers rather than safely use std::string.
Thank you!
I've research for half a day and cannot figure out how to pass a simple char pointer, and modify the value in a function. Most of the solutions say to modify the function to accept a char ** parameter.
I have a function I cannot modify. I need to pass a char pointer to it because this function will give me a new calculated char value. I was told I can pass a pointer to a char array and it will work, but I am unsure how to do it.
Passing char pointer as argument to function
I followed the above post and came up with the following code but it still does not work. When I pass the pointer to the char arr[] it does not change its value. My goal is to pass a char pointer and be able to write to it in another function by passing its reference. Any help is appreciated.
enum STATUS {
OK = 0,
BAD = 1,
};
STATUS func1(char *pData)
{
pData = "Hello World";
cout << pData << endl;
return OK;
}
int main()
{
STATUS ret;
char arr[] = "Example String";
char* pArray = &arr[0];
ret = func1(pArray);
cout << arr << endl;
cout << pArray << endl;
getchar();
return 0;
}
STATUS func1(char *pData)
{
pData = "Hello World";
cout << pData << endl;
return OK;
}
That function is doing a shallow copy (ie. changing the value of the pointer pData and not what it points to). You need to do a deep copy of the new string into the memory pointed to by the pData pointer.
The traditional way to do a deep copy of a string is to use the strcpy() library call. You could also use a loop.
I have a function I cannot modify. I need to pass a char pointer to it because this function will give me a new calculated char value. I was told I can pass a pointer to a char array and it will work, but I am unsure how to do it.
That is not true. Whoever said that is lying to you or they are ignorant of the subject matter.
When you use
pData = "Hello World";
you are modifying where pData points to. However, that change is local to the function. It does not change the data in the calling function. You can use std::strcpy for the change to affect the calling function.
std::strcpy(pData, "Hello World");
You can pass the pointer by reference and change the value of the pointer. That will make the change visible to the calling function.
STATUS func1(char*& pData)
{
pData = "Hello World";
cout << pData << endl;
return OK;
}
However, when you do that, arr and pArray in main will be different. arr will continue to have the same value while pArray will point to a completely different value.
STATUS func1(char *pData)
{
*(pData) = "H";
*(pData+1) = "e";
*(pData+2) = "l";
*(pData+3) = "l";
//... etc ...
cout << pData << endl;
return OK;
}
This is changing the memory the pointer points to, not the pointer itself. It can be done better using the functions in the other answers but this is more explicit. If you're using an IDE that allows single step debugging and memory viewing, you can watch the individual bytes in memory change.
This might lead to pointer over runs if the initial memory buffer isn’t big enough.
Also worth mentioning, is your memory big enough for the function you cannot change? Should you allocate memory like this:
char *ptr = new char[1000];
//etc....
if(ptr) delete ptr;
To create (and delete) a bigger, uninitialised memory buffer?
Not really sure what's going on here, I'm using Clion as my IDE which I don't believe has anything to do with this but I figured I'd add that information. My confusion comes from a function that I wrote
int Arry()
{
int Mynumbers [5] = {10};
std::cout << Mynumbers;
}
something simple. It should be assigning 5 integers the value of 10. But when I print out Mynumbers I am shown the memory address. Why is this happening, I thought that was what calling pointers was for. Thank you for your time.
Sincerely,
Nicholas
It is a bit complicated, and there are a few issues at play:
std::cout (actually, std::ostream, of which std::cout is an instance, does not have an overload of operator<< that understands plain arrays. It does have overloads that understand pointers.
In C++ (and C) an array name can be used as an expression in a place where a pointer is needed. When there is no better option, the array name will decay to a pointer. That is what makes the following legal: int a[10] = {}; int* p = a;.
The overload that takes a pointer prints it as a hexadecimal address, unless the pointer is of type char* or const char* (or wchar versions), in which case it treats it as a null terminated string.
This is what is happening here: because there isn't an operator<< overload that matches the array, it decays to the overload taking a pointer. And as it isn't a character type pointer, you see the hexadecimal address. You are seeing the equivalent of cout << &MyNumbers[0];.
Some notes:
void Arry() // use void if nothing is being returned
{
int Mynumbers[5] = {10}; // first element is 10, the rest are 0
//std::cout << Mynumbers; // will print the first address because the array decays to a pointer which is then printed
for (auto i : Mynumbers) // range-for takes note of the size of the array (no decay)
std::cout << i << '\t';
}
In C++, you can think of an array as a pointer to a memory address (this isn't strictly true, and others can explain the subtle differences). When you are calling cout on your array name, you are asking for it's contents: the memory address.
If you wish to see what's in the array, you can use a simple for loop:
for (int i = 0; i < 5; i++)
std::cout << Mynumbers[i] << " ";
The value of Mynumbers is in fact the adress of the first element in the array.
try the following:
for(int i=0; i<5;i++) {
cout << Mynumbers[i];
}
I'm looking for a way to associate a char array with a string so that whenever the char array changes, the string also changes. I tried to put both char array and string variables in a union but that didn't worked as the compiler complained...
Any ideas are welcome...
class Observable_CharArray
{
char* arr;
std::function<void(char*)> change_callback;
public:
Observable_CharArray(int size, std::function<void(char*)> callback)
: arr(new char[size]), change_callback(callback){}
~Observable_CharArray()/*as mentioned by Hulk*/
{
delete[] arr;
}
void SetCallback(std::function<void(char*)> callback)
{
change_callback = callback;
}
/*other member function to give access to array*/
void change_function()
{
//change the array here
change_callback(arr);
}
};
class Observer_String
{
std::string rep;
void callback(char* cc)
{
rep = std::string(cc);
}
public:
Observer_String(Observable_CharArray* och)
{
och->SetCallback(std::bind(&callback, this, _1));
}
/*other member functions to access rep*/
};
The design can definitely be improved.
There can be other ways to solve your actual problem rather than observing char arrays.
The problem is that the std::string may change the string array inside (especially when it resizes). For instance, c_str returns the address of the current string - documentation says that "The pointer returned may be invalidated by further calls to other member functions that modify the object.".
If you're sure you won't call string methods (hence the string will stay at the same memory location), you could try accessing the c_str pointer (your char array) directly and modify its content.
std::string str = "test";
char* arr = (char*)str.c_str();
arr[3] = 'a';
NOTE: I strongly advice against this unless in a testing context.
In other words, the string class doesn't guarantee it's going to stay in the same place in memory - meaning trying to access it through a char array is impossible.
The best is to create another string class that enforces the char array to always stay the same size (and so can stay in the same memory position all the time). You could also create a bigger array (max size string for instance) to cope with any string size changes - but that should be enforced in your wrapper class.
Well you can do this, but you shouldn't
#include <iostream>
#include <string>
int main()
{
std::string test("123456789");
std::cout << test << "\n";
char* data = &test.front(); // use &(*test.begin()) for pre-C++11 code
for ( size_t i(0); i < test.size(); ++i )
{
data[i] = 57 - i;
}
std::cout << test << "\n";
}
Output will be
123456789
987654321
This however goes again everything std::string is trying to facilitate for you. If you use data, you risk causing UB and changes to test may make data point to garbage.
You should not do this!
However, there are many (dangerous) ways to achieve it:
char* cStr = const_cast<char*>(cppStr.c_str());
or
char* cStr = const_cast<char*>(cppStr.data());
or
char* cStr = &cppStr[0];
But beware that the cppStr might be reallocated whenever you touch it, hence invalidating your cStr. That would crash at some point in time, although maybe not immediately (which is even worse).
Therefore, if you are going to do this anyway. Make sure to cppStr.reserve(SOMETHING) *before* you get the cStr out of it. This way, you will at least stabilise the pointer for a while.