Is it possible to add a string to a string pointer in C++?
Not working example:
String* temp;
temp[0] = "string";
Just like it's possible in:
String temp[3];
temp[0] = "string";
Before suggesting to just use a normal array or copy it to a different fixed array, the string pointer needs to be returned in a function. Eg.
String* SomeClass::toArray(String str)
I am also open to other suggestions how I can return an array from this function.
Independing of what is String this code snippet
String* temp;
temp[0] = "string";
if it is compiled results in undefined behaviour because the pointer temp either has an indeterminate value (if it is a local variable) or NULL and you may not derefence it.
Provided that this code snippet
String temp[3];
temp[0] = "string";
is valid you could write for example
String* other_temp = temp;
other_temp[0] = "string";
you can't add anything to POINTER, pointer is just pointing to some memory.
You need first to have some instance, like in your second example String temp[3]; you are creating three instances of String.
So String temp; will create local instance of String, then to get it's pointer you can use String * tempPtr = &temp;, but I don't see why you would want that, as you can use temp as is... like temp.clear(); or whatever functions the class String has (see it's API).
Edit about returning String pointer.
That's sort of unfortunate C++ API design. So who will own the memory of that instance?
For example:
String* SomeClass::toArray(String str) {
String result;
// BUG, DO NOT DO THIS!
return &result; // returns pointer to local stack variable
// which gets released *here*, invalidating the pointer
}
String* SomeClass::toArray(String str) {
String *result = new String;
return result; // returns pointer to global heap
// now if the upper layer of code will not call "delete" on it
// you have memory leak
}
BTW, from the "toArray" name it looks like you want array of String instances, not String pointer. So that functions should be rather defined as String[] SomeClass::toArray(String str), still having the same problem with memory ownership.
What I would do is not return an array.
maybe void SomeClass::toArray(const String & str, std::vector<String> & array), filling up the data into array vector.
I do not know how much you use C++ on arduino, if std::vector is OK, or not, but having a class for String feels like vector<> will be OK too, especially if you are wasting your stack by passing copy instance of String instead of reference. (unless String is some macro/typedef for char[], please, don't tell me that... I mean, even C++ can be written in low memory footprint way, you don't have to hardwire arrays everywhere, if you avoid unnecessary allocation of temporary instances of C++ classes).
Related
I am using c++.
I want to initialize pointer of string. I have been doing it using :
string *strPtr = new string("abcd");
But I don't want to use heap memory. Use somthing like this :
string *strPtr;
// initialize with "abcd"
How can I do it using stack memory?
You can declare a string on the stack and then take the address of it:
std::string str{"abcd"};
std::string* ptr_str = &str;
But I'm sure it would be more convenient for you to handle a reference, a smart pointer, or maybe a std::string_view. Raw pointers should be used in some very specific cases nowadays.
Like this:
string str("abcd");
string *strPtr = &str;
Sometimes you can get away with using alloca() to allocate memory on the stack, you'd need to allocate twice, once for metadata and once for data and then reinterpret_cast...
I've written a function that takes a string and returns a const char * which contains an encoded version of that string. I call this function, and then create a new string. In doing so, I am somehow inadvertently changing the value pointed to my const char *, something which I thought was impossible.
However, when I don't use my own function, but just hardcode a value into my const char array, the value does not change when I create a string. Why is there a difference here, and why would I be able to change the value of a const char array anyways?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <iostream>
using namespace std;
// returns "#username#FIN"
const char* encodeUsername(string username)
{
username = "#" + username + "#FIN";
return username.c_str();
}
int main(void)
{
string jack("jack");
const char* encodedUsername = "#jack#FIN";
string dummy("hi");
printf("%s\n", encodedUsername); //outputs "#jack#FIN", as expected.
string tim("tim");
const char* encodedUsername2 = encodeUsername(tim);
string dummy2("hi");
printf("%s\n", encodedUsername2); //outputs "hi". Why?
}
To understand why this happens you need to understand several intrinsic properties of C++.
In C++ pointers can point to areas of memory that were freed up. This is something you cannot do in many other languages, and it can hide some severe errors. For example, consider the following code:
char* moo()
{
char* a = new char[20];
strcpy(a, "hello");
delete[] a;
return a;
}
Note that even though I just deleted a, I can return a pointer to it. The calling side will receive that pointer and will have no idea that it points to a freed-up memory. Moreover, if you immediately print the value of the returned value, you will very likely see "hello", because delete usually does not zero-out memory it frees up.
std::string is, roughly speaking, a wrapper around char* that hides all the allocations and deallocations behind a very nice interface, so that you don't need to care about memory management. The constructor of std::string and all operations on it allocate or reallocate the array, and the destructor deallocates it.
When you pass something into a function by value (as you do in your encodeUsername function in line username = "#" + username + "#FIN"), it creates a new object with a copy of what you are passing, which will be destroyed as soon as the function ends. So in this case, as soon as encodeUsername returns, username is destroyed, because it was passed by value, and is contained within the function's scope. Since the object is destroyed, its destructor is called, and at that point the string is deallocated. The pointer to the raw data that you retrieved by calling to c_str() now points to something that does not exist any longer.
When you allocate an object immediately following a deallocation, you are very likely to reuse the memory of the object that was just freed. In your case, as you create a new string, tim, it allocates memory at the same address that was just deallocated when encodeUsername returned.
Now, how can you fix it?
First, if you don't care about the input string (as, if you are OK with overwriting it), you can just pass it by reference:
const char* encodeUsername(string& username)
This will fix it, because username is not a copy, so it is not destroyed at the end of the function. The problem now, however, is that this function will change the value of the string you are passing in, which is very undesirable and creates an unintuitive interface.
Second, you can allocate a new char array before returning it, and then free it at the end of the calling function:
const char* encodeUsername(string username)
{
username = "#" + username + "#FIN";
return strdup(username.c_str());
}
and then at the end of main:
free(encodedUsername);
free(encodedUsername2);
(note that you have to use free and not delete[] because the array was allocated using strdup)
This will work because the char array we return is allocated on the heap right before we return and is not freed. It comes at a price that now the calling function need to free it up, which is, again, an unintuitive interface.
Finally, the proper solution would be to return an std::string instead of a char pointer, in which case the std::string will take care of all the allocations and deallocations for you:
string encodeUsername(string username)
{
username = "#" + username + "#FIN";
return username;
}
And then in the main function:
string encodedUsername2 = encodeUsername(tim);
printf("%s\n", encodedUsername2.c_str());
The lifetime of username terminates when encodeUsername returns, leaving the pointer returned by that function dangling. In other words, it is Undefined Behaviour, which in this case manifests itself in the reuse of the memory pointed to by encodeUsername's return value for the newly-created string.
That won't happen if you return the std::string itself.
How do I do this thing.
char* ToString(int num) {
char* str = new char[len(num)];
//conversion
return str;
}
And by calling this.
string someStr = ToString(someInt);
Should I free the someStr here?
I know I always need to delete whenever I use new.
And what if I call this function multiple times, do I allocate memory and just leaving them behind not using it?
You should avoid this practice altogether. Either return a std::unique_ptr, or deal with std::string directly. It is not clear from your code what exactly you are trying to do, so I can't offer specific solutions.
Note that this initialization:
string someStr = ToString(someInt);
will only work properly if you return a null-terminated string, but it leaks resources regardless.
See this related post.
You need to call delete once for every call to ToString. You also can't initialise a std::string with an allocated char array in the way your question hints at - that'd leak the returned memory, with your someStr variable having copied it.
The easiest/neatest thing to do would be to change ToString to return std::string instead. In this case, memory used by the string will be automatically deleted when the caller's variable goes out of scope.
I ran your code under valgrind with --leak-check=full, it reports num size of memory leak.
Call new/delete, new [] /delete [] in pair is the only way to keep memory cycled.
I am not sure what's you trying to do, if you want to convert integer types to string, C++ has a few options:
// std::to_string(C++11) e.g:
{
std::string str = std::to_string(num)
}
// std::stringstream e.g:
{
std::string str;
std::stringstream ss;
ss << num;
ss >> str;
}
// boost::lexical_cast e.g:
{
std::string str = boost::lexical_cast<std::string>(num);
}
// itoa(c function)
{
char buf[MAX_INT_DIGITS]; // MAX_INT_DIGITS == 12 ("-2147483648\0")
itoa(num, buf, 10);
std::string str(buf);
}
You're ToString function should return a std::string, if you then just assign the value to a std::string. No reason to deal with dynamically allocated memory here.
someStr is a copy. You have allready a leak. You need to temporally save the value of the returned pointer and after constructing the string delect it. This is normaly the job of the smart pointers.
EDIT:
No,
char* temp = strs; delete [] str; return temp;
will something undefined. But:
char* temp =ToString(someInt); string someStr(temp);delete []temp;
will work. But this is only for you to understand the idea. This can be made for you if you return a unique_ptr. And I'm assuming this is a kind of general question of returning a memory that have to be free after that, in with case unique_ptr and shared_ptr are a solution. In this particular case you can just create a string, modify it and return it simply. All the memory manage will be made for you by the string class. If you really only need to allocate “space” in the string, you can do:
String Str; Str.reserve(len(num));
I want to store the static value in string pointer is it posible?
If I do like
string *array = {"value"};
the error occurs
error: cannot convert 'const char*' to 'std::string*' in initialization
you would then need to write
string *array = new string("value");
although you are better off using
string array = "value";
as that is the intended way to use it. otherwise you need to keep track of memory.
A std::string pointer has to point to an std::string object. What it actually points to depends on your use case. For example:
std::string s("value"); // initialize a string
std::string* p = &s; // p points to s
In the above example, p points to a local string with automatic storage duration. When it it gets destroyed, anything that points to it will point to garbage.
You can also make the pointer point to a dynamically allocated string, in which case you are in charge of releasing the resources when you are done:
std::string* p = new std::string("value"); // p points to dynamically allocated string
// ....
delete p; // release resources when done
You would be advised to use smart pointers instead of raw pointers to dynamically allocated objects.
As array is an array of strings you could try this:
int main()
{
string *array = new string[1];
array[1] = "value";
return 0;
}
You can explicitly convert the literal to a string:
std::string array[] = {std::string("value")};
Note that you have to define this as an array, not a pointer though. Of course, an array mostly makes sense if you have more than one element, like:
string array[] = {string("value1"), string("value2"), string("etc")};
Okay the previous question was answered clearly, but i found out another problem.
What if I do:
char *test(int ran){
char *ret = new char[ran];
// process...
return ret;
}
And then run it:
for(int i = 0; i < 100000000; i++){
string str = test(rand()%10000000+10000000);
// process...
// no need to delete str anymore? string destructor does it for me here?
}
So after converting the char* to string, I don't have to worry about the deleting anymore?
Edit: As answered, I have to delete[] each new[] call, but on my case its not possible since the pointer got lost, so the question is: how do I convert char to string properly?
Here you are not converting the char* to a [std::]string, but copying the char* to a [std::]string.
As a rule of thumb, for every new there should be a delete.
In this case, you'll need to store a copy of the pointer and delete it when you're done:
char* temp = test(rand()%10000000+10000000);
string str = temp;
delete[] temp;
You seem to be under the impresison that passing a char* into std::string transfers ownership of the allocated memory. In fact it just makes a copy.
The easiest way to solve this is to just use a std::string throughout the entire function and return it directly.
std::string test(int ran){
std::string ret;
ret.resize(ran - 1); // If accessing by individual character, or not if using the entire string at once.
// process... (omit adding the null terminator)
return ret;
}
Yes, yes you do.
If you are using linux/os x, look into something like valgrind which can help you with memory issues
You can change your test function so that it returns a string instead of char *, this way you can delete [] ret in the test function.
OR you could just use a string in test as well and not have to worry about new/delete.
You must call delete for every new otherwise you will leak memory. In the case you have shown you are throwing away the pointer, if you must leave the function as returning a char* then you will need to use two lines to create the std::string so you can retain a copy of the char* to delete.
A better solution would be to rewrite your test() function to return a std::string directly.
You need to do something like this:
for(int i = 0; i < 100000000; i++){
int length = rand()%10000000+10000000;
char* tmp = test(length);
string str(tmp);
delete[length] tmp;
}
This deletes the allocated char-array properly.
By the way, you should always zero-terminate a string if you create it this way (i.e. inside the function test), otherwise some functions can easily get "confused" and treat data behind your string as part of it, which in the best case crashes your application, and in the worst case creating a silent buffer overflow leading to undefined behaviour at a later point, which is the ultimate debugging nightmare... ;)