C++ const string literals and custom string class - c++

In C++ string literals "Hello" are const and are immutable. I wanted to make a custom string class whose strings are not const chars, so they can be changeable
Here is a snippet of code that might illustrate what I'm trying to do:
#include <iostream>
class String {
public:
char * p_start;
String(char * strSourc) // Constructor
{
p_start = strSourc;
}
};
int main()
{
String myString("Hello");
// Create object myString, send "Hello" string literal as argument
std::cout << myString.p_start << std::endl;
// Prints "Hello"
*myString.p_start = 'Y';
// Attempt to change value at first byte of myString.p_start
std::cout << myString.p_start << std::endl;
// Prints "Hello" (no change)
myString.p_start = "Yellow";
// Assigning a string literal to p_start pointer
std::cout << myString.p_start << std::endl;
// Prints Yellow, change works. I thought myString "Hello" was const chars, immutable
return 0;
}
So, I'm confused. I've looked everywhere and it says that string literals, like "Hello", are immutable, each of their char bytes are unchangeable. Though I managed to assign Yellow to the p_start pointer, changing the first letter. Though changing the single letter H to a Y through dereferencing the H pointer didn't do anything.
Any insights would help me, thanks.

I think you're confusing about pointer and pointee.
p_start = "Yellow", you're changing the value of pointer, to point to "Yellow". *p_start = 'Y', you're changing the value of pointee, the content p_start points to, not itself. As you said, "Yellow" are const chars, so the behaviour try to modify them is UB.
You can make a copy of it in the ctor, then you can modify the chars, which are managed by the class. Yes, it will be a new copy, but it won't be a waste of memory. And you have no choice if you want them to be changable.

not sure if anyone finds this helpful after so long but since I am learning myself I took your above code and made it work by copying. It now has a member variable for size and cleans up using delete when you assign a new string literal to it (const char*).
#include <iostream>
class String {
public:
char * p_start;
int m_size;
String(const char * strSourc) // Constructor
{
//The following will get the size of the parameter.
int SizeParameter=0;
while (*(strSourc+SizeParameter) != '\0')
{
SizeParameter++;
}
// size of string saved.
m_size = SizeParameter;
// allocate enough memory so we can copy strSourc
p_start = new char[SizeParameter+1];
//copy the contents strSourc
for(int i=0; i<SizeParameter+1; i++)
{
*(p_start+i) = *(strSourc+i);
}
}
//Handle change of string value.
char* AssignNewString (const char* newtext)
{
//clean
delete p_start;
int SizeParameter=0;
while (*(newtext+SizeParameter) != '\0')
{
SizeParameter++;
}
// size of string saved.
m_size = SizeParameter;
// allocate enough memory so we can copy strSourc
p_start = new char[SizeParameter+1];
//copy the contents strSourc
for(int i=0; i<SizeParameter+1; i++)
{
*(p_start+i) = *(newtext+i);
}
return p_start;
}
char* operator=(const char* newtext)
{
AssignNewString(newtext);
}
};
int main()
{
String myString("Hello");
// Create object myString, send "Hello" string literal as argument
std::cout << "string size: " << myString.m_size << std::endl;
std::cout << myString.p_start << std::endl;
// Prints "Hello"
*myString.p_start = 'Y';
// Attempt to change value at first byte of myString.p_start
std::cout << myString.p_start << std::endl;
// Prints "Hello" (no change)
myString = "yellow";
// Assigning a string literal to p_start pointer
myString = "THIS IS A LONGER STRING";
std::cout << myString.p_start << std::endl;
std::cout << "string size: " << myString.m_size << std::endl;
return 0;
}
Note I am learning myself so do let me know if I am doing something wrong. But so far, it seems to work.

Related

C++ MFC missing const char* variable

So I have that simple code inside button click method:
std::stringstream ss;
unsigned counter = 0;
while(true)
{
ss.clear();
ss << DEFAULT_USER_CONFIG_NAME << " " << ++counter;
const char* name = ss.str().c_str();
MessageBox(name);
/* ... while break condition */
}
The problem is that messagebox is empty. But it works correctly when I pass text directly:
MessageBox(ss.str().c_str()); // that shows text just fine
What I found with debugger is that local variable "name" is not created(at least it is not showing in debugger). Any clue why it is working when passed directly and failing otherwise? Also when i casted "name" to CString it returned true on IsEmpty() check.
The expression ss.str() creates a temporary std::string object. Storing the result of c_str() thus points to memory of a temporary, which quickly turns into a dangling pointer. Once the full expression statement
const char* name = ss.str().c_str();
// ^ this is where the temporary ss.str() gets destroyed.
is evaluated, the temporary gets destroyed.
You already know, how to solve this, by placing the expression creating the temporary inside the full expression, that consumes it. This extends the lifetime of the temporary until the end of the full expression:
MessageBox(ss.str().c_str());
// ^ this is where the temporary ss.str() gets destroyed.
The following illustrates the sequence of events. Let's just define a few placeholder classes and functions:
void messagebox(const char*) {
cout << "messagebox()" << endl;
}
struct tmp {
tmp(const char* content) : content(content) { cout << "tmp c'tor" << endl; }
~tmp() { cout << "tmp d'tor" << endl; }
const char* c_str() { return content.c_str(); }
private:
string content;
};
struct ss {
tmp str() { return tmp("test"); }
};
With this in place, your first version
ss s;
const char* name = s.str().c_str();
messagebox(name);
produces the following output:
tmp c'tor
tmp d'tor
messagebox()
Whereas the second version
ss s;
messagebox(s.str().c_str());
changes the sequence in the output:
tmp c'tor
messagebox()
tmp d'tor
(Live sample code)

C++ Concatenating const char * with string, only const char * prints

I am trying to cout a const char *
This is how I convert an int to a string and concatenate it with the const char*
char tempTextResult[100];
const char * tempScore = std::to_string(6).c_str();
const char * tempText = "Score: ";
strcpy(tempTextResult, tempText);
strcat(tempTextResult, tempScore);
std::cout << tempTextResult;
The result when printing is: Score:
Does anyone know why the 6 is not printing?
Thanks in advance.
As the docs for c_str say, "The pointer returned may be invalidated by further calls to other member functions that modify the object." This includes the destructor.
const char * tempScore = std::to_string(6).c_str();
This makes tempScore point to a temporary string that no longer exists. You should do this:
std::string tempScore = std::to_string(6);
...
strcat(tempTextResult, tempScore.c_str());
Here, you're calling c_str on a string that continues to exist.
You have marked this post as C++.
One possible C++ approach: (not compiled, not tested)
std::string result; // empty string
{
std::stringstream ss;
ss << "Score: " // tempText literal
<< 6; // tempScore literal
// at this point, the values placed into tempTextResult
// are contained in ss
result = ss.str(); // because ss goes out of scope
}
// ss contents are gone
// ... many more lines of code
// ... now let us use that const char* captured via ss
std::cout << result.c_str() << std::endl;
// ^^^^^^^ - returns const char*

Why doesn't the pointer for the char *str change when we reverse the string in this function?

I wrote a simple function to perform in place reversal:
void in_place_reverse(char *str){
if(!str || !(*str)){
return;
}
char *str_end = str+strlen(str)-1;
int temp;
while(str < str_end){
temp = *str;
*(str++) = *str_end;
*(str_end--) = temp;
}
}
I'm just wondering why when I do something like this:
char str[] = "Reverse me!";
cout << "Original: " << str << endl;
in_place_reverse(str);
cout << "Reversed: " << str << endl;
str wasn't changed inside of the function. The reason I ask is because the line *(str++) is incrementing the pointer that points to str. So what I'm really asking is why something like this isn't necessary:
char *str_beg = str;
char *str_end = str+strlen(str)-1;
int temp;
while(str_beg < str_end){
temp = *str_beg;
*(str_beg++) = *str_end;
*(str_end--) = temp;
}
So that we're not actually changing the pointer that points to the first position of str.
You actually are doing this implicitely because 'str' is passed by value (read: 'as a copy in a temporary variable').
To clarify this without the (distracting) pointer: consider
void increment(int x) {
x++;
}
int i = 1;
cout << i << endl;
increment(i);
cout << i << endl;
This will print '1' twice. The x that is seen inside the increment routine has the same value like the passed i. But it is not the same variable i. In fact it is a copy of i. When we return from the routine, the copy is discarded. Further reading: This would be different if we'd pass x by reference, like so:
void increment(int &x) {
x++;
}
The declaration of the function void in_place_reverse(char *str) results in a copy of the pointer being created when the function is called, in a variable called str that is private and local to the in_place_reverse. You can modify this value all you like without affecting the original that exists in the scope of the calling function.

const char* Return Type

I have a function which returns a const char*
const char* SayHi()
{
string data="Mustafa Hi";
const char* cptr=data.c_str();
return cptr;
}
int main()
{
cout<<SayHi()<<endl;
return 0;
}
But output is not :
Mustafa Hi. It is null.
If i define data variable as global like
string data;
const char* SayHi()
{
data="Mustafa Hi";
const char* cptr=data.c_str();
return cptr;
}
int main()
{
cout<<SayHi()<<endl;
return 0;
}
Output is Mustafa Hi.
But for const int* this works;
const int* aMethod()
{
int* aVar=new int(111);
const int* acstPtr=aVar;
return acstPtr;
}
int main()
{
cout<<*aMethod()<<endl;
return 0;
}
Output : 111
or
const int* aMethod()
{
int aVar =111; //in stack
const int* acstPtr=&aVar;
return acstPtr;
}
so why not null?
The problem with your first implementation is that you return a pointer to temporary memory. Because the 'string data' variable is only defined within the scope of that function, when the function goes away, the pointer that you just returned is now pointing to free'd memory. In your case, it must be being overwritten with all zeros. That is why you are seeing NULL.
Because in C++ objects have a lifetime. In your first example the string no longer exists once you exit the function. Therefore it's an error to return a pointer to that string's data.
You need to understand that "string data" inside of SayHi is a local variable. When the function exits local variables are destroyed.
To do what you're trying to do you either have to create the storage for the string so that it is not local to SayHi, either in main and pass it in or on the heap. Perhaps you'd like SayHi to return a reference.
Try the code below. If you want to return a pointer to a local variable, you need to use a static keyword. All local variable will be free after it exist the function. That is the reason are not able to get the string properly return.
const char* SayHi()
{
static string data="Mustafa Hi";
const char* cptr=data.c_str();
return cptr;
}
But output is not : Mustafa Hi. It is null.
It could be anything. Issue is with returning the member variable (const char *) of a local object (string), which will be cleaned once we come out of the enclosing curly brace. Output is undefined in such cases. On few compilers you may even get the desired output if the the memory that was released was not reallocated.
It works for global variable because they span throughout the life time of the program and is not cleaned up after the control exits SayHi()
const int* this works;
This is dynamic memory allocation as against the stack allocation earlier. Unlike stack allocation (creating local object), with heap allocation (using new) you have the memory and the value until you delete the memory explicitly.
To replicate the first scenario with int, your code should be something like,
const int* aMethod()
{
int aVar=111; // changed from pointer to local variable. Heap to stack
const int* acstPtr= &aVar; //Returning the address for local variable. Which will be freed at the enclosing curly brace.
return acstPtr;
}
But again, output is undefined when you deal with pointers whose memory is already freed (dangling pointer)
Local variables are created on the "stack", which have a lifetime of the scope they exist in. In particular, what is happening in your original case:
string data="Mustafa Hi";
const char* cptr=data.c_str();
return cptr;
is complicated by the fact thatstd::string is an object with a destructor. Prior to C++11, it may have stored the string without the terminating zero unless you called c_str(). Internally, it contains a pointer and a size value and perhaps also a capacity value. It allocates memory to store the string. Think of (pre-C++11) std::string like this:
class String {
char* m_ptr;
size_t m_length;
size_t m_alloc;
public:
String() : m_ptr(nullptr), m_length(0), m_alloc(0) {}
String(const char* src) {
size_t length = strlen(src);
m_ptr = new char[length];
m_alloc = m_length;
memcpy(m_ptr, src, length); // not including the \0
}
const char* c_str() {
if (m_length == 0)
return nullptr;
if (m_alloc > m_length) // we're null terminated
return m_ptr;
char* newPtr = new char[length + 1];
memcpy(m_ptr, newPtr, length);
delete [] m_ptr;
m_ptr = newPtr;
m_ptr[length] = '\0';
++m_alloc;
return m_ptr;
}
~String() {
#ifdef _DEBUG
if (m_ptr) m_ptr[0] = 0;
#endif
delete [] m_ptr;
}
};
Your function is taking the address of an instance of this object, then returning that address. The next thing that happens is that the instance goes out of scope and calls it's destructor -- it was on the stack and immediately after your code, so the stack location it was in is now available for use by whatever code gets called next.
Take a look at the following sample (live demo: http://ideone.com/wAcY3B)
#include <iostream>
int* getInt1(int input)
{
int i = input;
std::cout << "created 'i' at " << (void*)&i << std::endl;
int* ptr1 = &i;
return ptr1;
}
int* getInt2(int input)
{
int* ptr3 = new int(input);
return ptr3;
}
int main()
{
int i = 0;
std::cout << "i is on the stack, it's address is " << (void*)&i << std::endl;
int* ip = new int(1);
std::cout << "ip is on the heap, it's address is " << (void*)ip << std::endl;
int* p1 = NULL;
int* p2 = NULL;
int* p3 = NULL;
// force the pointers to be assigned locations on the stack by printing them.
std::cout << "created p1(" << &p1 << "), p2(" << &p2 << ") and p3(" << &p3 << ")" << std::endl;
p1 = getInt1(10101);
std::cout << "p1(" << &p1 << ") = " << (void*)p1 << " -> " << *p1 << std::endl;
p2 = getInt1(20202);
std::cout << "p2(" << &p2 << ") = " << (void*)p2 << " -> " << *p2 << std::endl;
// but more importantly
std::cout << "p1(" << &p1 << ") = " << (void*)p1 << " -> " << *p1 << std::endl;
p3 = getInt2(30303);
std::cout << "p3(" << &p3 << ") = " << (void*)p3 << " -> " << *p3 << std::endl;
std::cout << "p2(" << &p2 << ") = " << (void*)p2 << " -> " << *p2 << std::endl;
std::cout << "p1(" << &p1 << ") = " << (void*)p1 << " -> " << *p1 << std::endl;
}
Output looks like this:
i is on the stack, it's address is 0xbfb49a90
ip is on the heap, it's address is 0x9b83008
created p1(0xbfb49a94), p2(0xbfb49a98) and p3(0xbfb49a9c)
created 'i' at 0xbfb49a6c
p1(0xbfb49a94) = 0xbfb49a6c -> 10101
created 'i' at 0xbfb49a6c
p2(0xbfb49a98) = 0xbfb49a6c -> 20202
p1(0xbfb49a94) = 0xbfb49a6c -> -1078682988
p3(0xbfb49a9c) = 0x9b83018 -> 30303
p2(0xbfb49a98) = 0xbfb49a6c -> -1078682988
p1(0xbfb49a94) = 0xbfb49a6c -> -1078682988
Because the stack pointer doesn't change between calls to "getInt1()" it's local variable instances are in the same location, but if you call some other random functions in-between assignments, they will use the same stack location and your pointed-to-values will be lost.

What does new [size_t] + 1 return

The following sample of code if from a book "C++ von A bis Z" (second edition, translation: C++ from A to Z) at page 364. The sample is wrong.
// overload operator +=
#include <iostream>
#include <cstring>
using namespace std;
class String {
private:
char* buffer;
unsigned int len;
public:
String(const char* s="") {
// cout << "Constructor: " << s << "\n";
len = strlen(s);
buffer = new char [len+1];
strcpy(buffer, s);
}
~String() {
// cout << "Destructor: " << buffer << "\n";
delete [] buffer;
}
String(const String& s) {
// cout << "Copy_Constructor: " << s.get_buffer() << "\n";
len = s.len;
buffer = new char [len+1];
strcpy(buffer, s.buffer);
}
char* get_buffer() const {
return buffer;
}
// returning a reference is more efficent
// String& operater+=(const String& str1)
String operator+=(const String& str1) {
// cout << "Assignment_Operator +=: " << str1.get_buffer() << "\n";
String tmp(*this);
delete [] buffer;
len = tmp.len + str1.len;
// invalid pointer
// buffer = new char[len+1];
buffer = new char [len]+1;
strcpy(buffer, tmp.buffer);
strcat(buffer, str1.buffer);
// wrong return_type
// return *this;
return buffer;
}
};
int main(void) {
String string1("Adam");
String string2("Eva");
string1+=" und ";
string1.operator+=(string2);
cout << string1.get_buffer() << "\n";
return 0;
}
The lines with the comments are my "fixes". Now I want to know what "new char [len]+1" does? I think the following:
it allocates sizeof(char)*len memory from heap
and returns the WRONG address to the pointer *buffer
but what is the wrong address: "first address of the new memory on heap + 1" or "first address of the new memory on heap + sizeof(char)*1)?
What happens?
Thanks
// edit
Thank you all! You helped me!
I just wanted to know, what this statement will return.
new char [len]+1;
The line itself is, of course, a typo from the author of the book.
Let's break it down:
new char[len];
returns a pointer to an array of char.
new char[len] + 1;
returns the next address in memory.
It's basically cutting off the first character.
EDIT: As others have mentioned, this is most probably a typo, it should be new char[len+1]. I'm just explaining what the code does, but you should only use pointer arithmetics if you really know what you're doing. Trying to delete the returned pointer would be UB, as cHao pointed out. You'll also get UB if len == 1 and attempt to work with the returned pointer.
If you add an integer i to a T*, this will add sizeof(T) * i to the pointer. So in this case, since new char[len] returns a char*, + 1 will indeed add sizeof(char) * 1 to it.
new Type[size] + 1 will allocate an array of size size and yield the address of the element with index 1 - that the second element. Nothing special, just pointer arithmetic. new[] would yield the address of the element with index 0 and size +1 is done on that address it yields address of element with index 1.
It simply returns the pointer to the second array item =)
Read about C pointers ;)
+sizeof(char)*1, but I failed to see why did you do it.
I think it's a typo, and it should be new char [len+1]. The +1 is for the string terminator character that must exist.