Can't iterate over an array stored in Smart Pointers - c++

Suppose i have the following piece of code:
std::shared_ptr<char*> getString()
{
char hello[] = {'h','e','l','l','o'};
return std::make_shared<char*>(hello);
}
int main()
{
std::shared_ptr<char*> shared_str = getString();
std::cout<< (*shared_str)<<std::endl;//OK
std::cout<<(*shared_str)<<std::endl;//KO
return 0;
}
I don't know why I get just the first printing, while the second is in error. For the same reason I cannot iterate over such smart pointers like the following :
for(int i = 0; i < 5; i++)
std::cout<<(*shared_str)[i];
because also in this case, just the letter 'h' would be printed.
I am really confused about smart pointers and i didn't find that much since most of the explenations are about the handling of the life-time of referenced objects.
To summarize : error happens because the "hello" array goes out of scope, in fact, make_shared allocates memory dynamically for a char*, and stores inside the pointer "hello",however the array itself is going to die as the function geString() ends.

You have undefined behaviour in your code. This line:
return std::make_shared<char*>(hello);
assign hello to the shared pointer which you are returning, but this is a local array which does not exist after returning. Also shared_ptr will delete this pointer once its reference count reaches zero which is another UB.
The easiest solution is to use std::string:
std::shared_ptr<std::string> getString()
{
char hello[] = {'h','e','l','l','o', '\0'};
return std::make_shared<std::string>(hello);
}

Related

How could I use a reference of a pointer when re-allocating memory?

Unlike in the C, as what i've learned about C++, there is no instruction realloc in C++ for it is not recommended. But when I was creating a function that concatenates strings and at the same time can be dynamically re-allocating the given strings' memory without using vector, I've come to need some code just like as the realloc instruction functioning.
So what i've come up with is that using a reference of a pointer(in the code char* &des) could adjust the size of memory by using the usual instruction of C++, new and delete. However, an error occured: "[Error] invalid initialization of non-const reference of type 'char*&' from an rvalue of type 'char*'" Why is it impossible to initialize char*& type with the type char*? Isn't it the same as a statement char* &des = str0? The total code is as follows:
void Mystrcat(char* &des, const char* src) {
int des_len = Mystrlen(des); // Mystrlen just returns the length of a string with the type unsigned int excluding null character
int src_len = Mystrlen(src);
char* temp_str = des;
des = new char[des_len + src_len + 1];
//a copy process
for(int i = 0; i < des_len; i++) {
des[i] = *(temp_str + i);
}
for(int i = des_len + 1; i < des_len + src_len + 1; i++)
des[i - 1] = *(src + i - des_len - 1);
}
int main() {
char str0[100] = "Hello";
Mystrcat(str0, ", World!");
std::cout << str0 << std::endl; //expecting "Hello, World!" to be printed
return 0;
}
What i've tried before is just writing the parameter char* des instead of char* &des. But unlike in main function, it was not possible to get the size of total str0 array in Mystrcat function by simply using sizeof. As a result, I thought it would be good to use pointer reference. I was expecting this a reference of a pointer parameter to be working properly because it is equal to the statement char* &des = str0.
The problem here is:
char str0[100] = "Hello";
str in this case has a pinned (static) memory address. It's immutable in terms of its address -- so to speak -- because it's not a pointer to a string, but an array of characters of a size that can be evaluated at compile-time (not dynamically allocated). Making str itself point to a different address makes no sense and invites a whole lot of chaos. Even modifying the original pointer address to a dynamically-allocated array is chaos since you need the original address to properly free it. Think of an array of T as T* const (the address is immutable even if the contents are mutable and even if dynamically allocated, you need to keep the original address unmodified).
But in general as a non-profit advertisement of sorts, I want to encourage embracing value semantics as much as you can over pointer/reference ones. So instead of:
void Mystrcat(char* &des, const char* src)
{
// Modify the address of 'des' in place.
}
You can do:
[[nodiscard]] char* Mystrcat(char* des, const char* src)
{
// Input an address to a string and return an address to a new string.
}
Then you can pass an address to your array, get a pointer to a new modified copy (same thing you were doing before), and store the pointer to the new array (along with freeing it when you're done). There's little benefit to modifying things in place if you're just going to allocate a new string anyway.
This is still ignoring the conventional advice that you should use std::string which is what I think you need now and wholeheartedly echo over all this low-level pointer stuff and manual heap allocation and deallocation (which can be disastrous without the use of RAII when combined with thrown exceptions) But later you might want to deviate from it if the SBO is too large or too small or if the SBO optimization is counter-productive, for example but that's diving deep into things like custom memory allocators and whatnot and something you typically reserve until you encounter profiler hotspots and really know what you're doing.

How to use double pointers in array

I am in a problem in which I have to write a function which will tokenize the array of characters and then return the array.... I cannnot understand how to use double pointers... The whole code is here:
#include<iostream>
using namespace std;
char** StringTokenize(char*);
int main()
{
char *string1=new char[50];
cout<<"Enter: ";
cin.getline(string1,50);
StringTokenize(&string1[0]);
return 0;
}
char** StringTokenize(char *string1)
{
int i = 0, j = 0;
char **tokenArray[50];
**tokenArray[0] = &string1[0];
while (string1[i] != '\0')
{
tokenArray[i] = string1[i];
i++;
if (string1[i] == ' ')
{
tokenArray[i] = '\n';
i++;
}
else
{
continue;
}
}
tokenArray[i] = '\0';
cout << tokenArray << endl;
return tokenArray;
}
Please help me and write this function for me... Remember that prototype of function should not change
and then return the array.
In C++, return type of a function cannot be an array.
char *string1=new char[50];
It's a bad idea to use bare owning pointers to dynamic memory. If the program compiled at all, you would be leaking memory. I recommend using std::string instead.
StringTokenize(&string1[0]);
&string1[0] is redundant. You indirect through a pointer, and then get the address of the result... which is the pointer that you indirected through.
int i = 0, j = 0;
You've declared j, but aren't using it for anything.
char **tokenArray[50];
The pointers to substrings should be pointers to char. It's unclear why your array contains pointers to pointers to char.
Note that these pointers are uninitiallised at the moment.
**tokenArray[0] = &string1[0];
**tokenArray[0] will indirect through the first uninitialised pointer and the behaviour of the program will be undefined. And the right hand side has the aforementioned redundancy.
And the types don't match. The type of left hand operand is char while the type of right hand operand is char*. This is ill-formed and meaningless. Your compiler should be telling you about bugs like this.
tokenArray[i] = string1[i];
tokenArray[i] = '\n';
tokenArray[i] = '\0';
The types don't match. The type of left hand operand is char** while the type of right hand operand is char. These are ill-formed and meaningless. Your compiler should be telling you about bugs like this.
return tokenArray;
This is wrong because
The types don't match. You're supposed to return a char**, but tokenArray is an array of char**.
Returning an automatic array would result in implicit conversion to pointer to first element (which is a char***) and the automatic array would be automatically destroyed after the function returns, so the returned pointer would be invalid.
prototype of function should not change
That's rather unfortunate since it prevents writing a well designed function. You will either have to use static storage for the array, or return an owning bare pointer to (first element of) dynamic array. Neither is a good idea.

How to use call by reference to get value of a char** type variable from a function in C++?

I am trying to print the following using the code as:
int main() {
char p[] = "hello";
char*t = p;
char**b = &t;
std::string s = b[0];
cout<<"string="<<s<<" b[0]="<<b[0];
}
The output I get is as expected:
string=hello b[0]=hello
Now the same thing I want to achieve using a function call in which I pass a variable by reference as:
void func(char**& p) {
char *k = (char*)malloc(8*sizeof(char));
k = (char*)"abc";
p = &k;
}
int main() {
char**j = NULL;
func(j);
std::string s1 = j[0];
cout<<s1;
}
Now I am getting a null string. What could be the reason and how to solve it ?
You have (at least) two problems:
The first is that you make p point to the local variable k.
The second is more subtle, and is that you reassign k losing the original memory you allocated and make k point to.
Then the usual spiel about never using arrays of char or pointers to char for strings, when you have std::string. And that you should never use malloc in C++, only new or new[]. And if you need new[] consider using std::vector instead (except for strings of course).
There is NO WAY to write code like this that follows any sort of standards of good programming. If you are serious about learning how to program you should abandon this mess and rewrite your code to do things the correct way. This is sort of mess is never necessary, even when interfacing with legacy code.
However the following 'works'
void func(char**& p) {
p = new char*;
*p = new char[8];
strcpy(*p, "abc");
}
And take note, I didn't need to use a cast.

Understanding pointers and local scope [duplicate]

This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Closed 8 years ago.
Suppose I have the following functions:
char* allocateMemory()
{
char str[20] = "Hello world.";
return str;
}
int* another()
{
int x = 5;
return &x;
}
int _tmain(int argc, _TCHAR* argv[])
{
char* pString = allocateMemory();
printf("%s\n", pString);
int* blah = another();
printf("%d %d \n", blah, *blah);
return 0;
}
The first printf prints random values, because str IS LOCAL SCOPE.
The second printf prints the proper values, with blah = address of blah, *blah = 5
Why is it that local scope only affects allocateMemory which deals with arrays, but not integer?
Why does the first printf (returning char* ) prints random values and is affected by local scope, but not the second one (returning int* )?
Both ways of accessing the local variables of a method which goes out of scope is Undefined Behavior. These are some valid ways:
char* allocateMemory()
{
char* str= malloc(sizeof(char) * 20); //assuming C
strcpy(str, "Hello World.");
return str; //Valid
}
const char* allocateMemory()
{
return "Hello world."; //Valid Hello World is in read only location
}
int* another()
{
int *x = malloc(sizeof(int)); //assuming C
*x = 5;
return x; //Valid
}
char str[20] = "Hello world.";
str is local to function allocateMemory() and is no more valid once you exit the function and hence accessing it out of its scope if undefined behavior.
int x = 5;
The same applies here also.
You can have your data on heap and return the pointer to it is valid.
char *allocatememory()
{
char *p = malloc(20); /* Now the memory allocated is on heap and it is accessible even after the exit of this function */
return p;
}
Change the first function to:
char* allocateMemory()
{
static char str[20] = "Hello world.";
return str;
}
and see the difference.
And now explanation:
When you return address of local data (variable or array, does not matter - it is AUTOMATIC variables) you have a risk to lose data or make a mess in the memory. It was just a good luck that integer data was correct after the second function call. But if you return address of STATIC variables - no mistakes. Also you can allocate memory from HEAP for data and return address.
These are both, of course, UB, as the other answerers said. They also gave some good ways to do what you want to do in a proper fashion. But you were asking why does this actually happen in your case. To understand it, you need to understand what happens in the stack when you call a function. I'll try to provide a really simplified explanation.
When a function is called, a new stack frame is created on top of the stack. All the data in the function is put onto the stack frame. So, for the function
char* allocateMemory()
{
char str[20] = "Hello world.";
return str;
}
The stack frame for allocateMemory will contain, besides some other stuff, the 20 elements of the string (char array) str.
For this function:
int* another()
{
int x = 5;
return &x;
}
The stack frame for another will contain the contents of the variable x.
When a function returns, the stack pointer, which marks the top of the stack, drops all the way down to where it was before a function invocation. However, the memory is still there on the stack, it doesn't get erased - it is a costy and pointless process. However, there is no longer anything protecting this memory from being overwritten by something: it has been marked "unneeded".
Now, what's the difference between your calls to printf? Well, when you call printf, it gets its own stack frame. It overwrites what was left of the previous called function's stack frame.
In the first case, you just pass pString to printf. Then printf overwrites the memory that once was the stack frame of allocateMemory, and the memory that was once str gets covered with stuff printf needs to work with string output, like iteration variables. Then it proceeds to try and get memory pointed to by the pointer you passed to it, pString... But it has just overwritten this memory, so it outputs what looks like garbage to you.
In the second case, you first got the value of the pointer blah, which resides in your local scope. Then you dereferenced it with *blah. Now comes the fun part: you've done the dereferencing before you've called another function which could overwrite the contents of the old stack frame. Which means the memory that was once the variable x in the function another is sort of still there, and by dereferencing the pointer blah, you get the value of x. And then you pass it to printf, but now, it doesn't matter that printf will overwrite another's stack frame: the values you passed to it are now sort of "safe". That's why the second call to printf outputs the values you expect.
I've heard of people who dislike using the heap so much that they use this "trick" in the following way: they form a stack array in a function and return a pointer to it, then, after the function returns, they copy its contents to an array in the caller's scope before calling any other function, and then proceed to use it. Never do this, for the sake of all the people who may read your code.

How to make char array and std::string "in a relationship"?

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.