I have a library function that requires an array of four pointers as parameter: f(unsigned char* data[4]), and I have an array of smart pointers in my code: std::unique_ptr<unsigned char> myArray[4].
Is there a way to use the smart pointers with this library function ?
I have already tried this but it gives me a segfault: f(reinterpret_cast<unsigned char **>(myArray[0].get()));
std::array<unsigned char* , 4> arr = { myArray[0].get(),myArray[1].get(),myArray[2].get(),myArray[3].get() };
pass arr.data().
Your cast is wrong. You are casting the unsigned char * pointer that is stored in the 1st array element. You would need to cast the address of the element itself:
f(reinterpret_cast<unsigned char **>(&myArray[0]));
Or even cast the array itself:
using puchar = unsigned char *;
f(reinterpret_cast<puchar(&)[4]>(myArray));
However, these only work because std::unique_ptr is designed to have no more storage overhead than a raw pointer. But it is undefined behavior to use these solutions. The correct solution is to simply copy the pointers to another array, eg:
unsigned char* myArrayOfPtrs[] = { myArray[0].get(), myArray[1].get(), myArray[2].get(), myArray[3].get() };
f(myArrayOfPtrs);
Or:
unsigned char* myArrayOfPtrs[4];
for (int i = 0; i < 4; ++i) {
myArrayOfPtrs[i] = myArray[i].get();
}
f(myArrayOfPtrs);
Or:
#include <algorithm>
unsigned char* myArrayOfPtrs[4];
std::transform(std::begin(myArray), std::end(myArray), std::begin(myArrayOfPtrs),
[](auto &p) { return p.get(); }
);
f(myArrayOfPtrs);
If you are sure that your unique_ptr will not be out of scope and want it to retain ownership of the associated pointers you can use char* a[] = {myArray[0].get(), myArray[1].get(), myArray[2].get(), myArray[3].get()} on each pointer in the array and create an array of regular pointers.
The unique_pointers retain ownership of the char* resource and if they go out of scope the unique_ptr destructor will free the pointers.
If you want to release ownership you can use the release() method on the unique_ptrs and this will allow you to safely convert to a regular pointer and ensure that the unique_ptr going out of scope will not deallocate the underlying char* resource.
release(): https://en.cppreference.com/w/cpp/memory/unique_ptr/release
get(): https://en.cppreference.com/w/cpp/memory/unique_ptr/get
Related
In C++, we can allocate heap memory for a dynamic array, but how can we initialize it if it's a read only array? Here is an example:
const char* str = new char[3];
After operating this statement, the system seems to initialize variable str with garbage value implicitly which means i cannot change its value since it has a constant qualifier. So how can i creat a constant string in heap memory and intialize it explicitly?
If i want to creat a object in heap memory, i need a pointer to the object. But if it's constant, i cannot even change it with the pointer after its creation in heap memory. So it became a vicious circle for me.
You can start with char * modify the array, then convert it to const char *:
char *str = new char[3];
// str[i] = ...
const char *cstr = str;
But unless you're trying to practice dynamic memory management, none of this should be necessary. Just use std::string or std::vector<char>.
Your operator new call doesn't allocate const memory. It gets converted to const when you assign it to the variable. The solution is to make a temporary variable that's not const, write the data to it and then finally convert it to a const pointer:
#include <cstring>
#include <memory>
std::unique_ptr<const char[]> PutBytesOntoHeap(const char* data, size_t size)
{
std::unique_ptr<char[]> result(new char[size]);
memcpy(result.get(), data, size);
return result;
}
In current c++ avoid calling new/delete explicitly, only use it internally in datastructures (and even then std::make_unique is prefered). So use std::vector (or alternatively std::string/std::string_view)
#273K Also note most C++ books (teachers, online material) are out of date.
#include <vector>
int main()
{
std::vector<char> str{ 'a', 'b', 'c' }; // this will do the memory allocation for you
// for local use (when a legacy api needs a pointer, otherwise don't use)
const char* ptr = str.data();
return 0;
// std::vector goes out of scope
// will free the allocated memory (so you can't forget to call delete[])
}
if it's constant, i cannot even change it with the pointer after its creation in heap memory
In
const char* str = new char[3];
you actually create a non-const char array and assign it to a const char*. You could just assign it to a char* instead, make the changes you want and then return a const char*. Example:
auto str = []() -> const char* {
char* rv = new char[3];
rv[0] = '1';
rv[1] = '2';
rv[2] = '\0';
return rv;
}();
how can i creat a constant string in heap memory and intialize it explicitly?
You use new const char[] with an initializer:
auto str = new const char[3]{'1', '2', '\0'};
A helper function could look like this:
#include <cstddef>
#include <iostream>
#include <utility>
template <std::size_t N>
auto make_const_cstring(const char (&s)[N]) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
return new const char[N]{s[Is]...};
}(std::make_index_sequence<N>());
}
int main() {
auto str = make_const_cstring("Hello world");
std::cout << str << '\n';
delete[] str;
}
If you want to use an array after the function that created it returns, allocate that array in the heap, not in the run-time stack. Expression new T[size] allocates a new array with size variables in it, each of type T. Remember that an array is treated just like a pointer to the first thing in the array. So expression new int[25] has type int*. Statement
int* A = new int[25];
allocates a new array of 25 ints and stores a pointer to the first one into variable A.
The size can be given by any expression that yields an integer. For example, if you already have an integer variable called n that currently holds 50, then
double* B = new double[n];
allocates an array of 50 doubles.
I am trying to solve a coding question that requires the results be returned using a given struct. The struct is defined as:
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
}
Where the lastNames is a pointer to last names that are each terminated by a non-alpha char. I can not seem to find any way to convert the vector of strings that I am using to compile all the last names into a variable that I can assign to lastNames. I have tried making a single string with all the last names and assigning it with c_str() like so:
Ans->lastName = allNames.c_str(); but this gives me an error. Due to the limitations of the question I am unable to change the struct variable to anything else. How can I assign a string to a const char* const*
The structure being used effectively uses a C-style approach to defining a variable sized array of pointers to char (with const sprinkled over it). You’ll need storage for both the array of char const* as well as the entities pointed to. Here is how you could build it from a std::vector<std::string>:
std::vector<std::string> strings = somehow_compute_the_strings();
std::vector<char const*> array;
for (std::string const& s: strings) {
array.push_back(s.c_str());
}
Answer answer = { array.data(), array.size() };
Of course, you can’t return answer without the pointer inside pointing to stale data: you’d need to keep the two std::vectors alive. Potentially these two objects could be made members of an object the function is called on. To actually return an object of type Answer without a place to hold on to the std::vectors you could allocate the relevant entities and accept that the result will yield a memory leak unless the caller can clean the result up.
You can't just cast stuff. struct Answer is expecting a char**, so you are going to have to build it and keep it valid as long as the struct Answer is in use. At least they were kind enough to let us know they don't intend to modify it or mess with cleaning up the memory, since it takes "const char * const *".
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
typedef std::vector<std::string> VectorOfStrings_type;
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
};
class AnswerWrapper
{
private:
// construct and maintain memory so the pointers in the Answer struct will be valid
char ** lastNames;
unsigned int numberOfPeople;
public:
AnswerWrapper(const VectorOfStrings_type &input){
numberOfPeople = input.size();
// create the array of pointers
lastNames = static_cast<char**>(
malloc(numberOfPeople * sizeof(char*))
);
// create each string
for (unsigned int i = 0; i < numberOfPeople; ++i){
const std::string &name = input[i];
// allocate space
lastNames[i] = static_cast<char*>(
malloc(name.size() + 1)
);
// copy string
strncpy(lastNames[i], name.data(), name.size());
// add null terminator
lastNames[i][name.size()] = '\0';
}
}
operator Answer (){
return Answer{ lastNames, numberOfPeople };
}
~AnswerWrapper(){
// critcally important, left as an exercise
assert(0);
}
};
void SomeFunctionWhichUsesAnswer(Answer a){
// presumably you have some legacy C code here
// but here's a quick and easy demo
for (unsigned int i = 0; i < a.numberOfPeople; ++i)
std::cout << a.lastNames[i] << std::endl;
}
int main() {
// Here is your vector of strings
VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
// You must construct a buffer for the "Answer" type, which must remain in scope
AnswerWrapper temp{ myData };
// AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
SomeFunctionWhichUsesAnswer(temp);
}
Also, I noticed that the strings in Answer are not referred to as null terminated. That is a separate issue you can take care of.
A const member variable can only be assigned in the constructor.
if you can add to the struct, define a constructor, and use the : lastname(value) syntax; or use the struct Answer myVar{value,number}; initialization, right where you declare your instance.
Another - ugly, dangerous, and frowned upon - alternative is a cast: (char**) lastname = value;, or in C++ syntax reinterpret_cast<char**>(lastname) = value.
If someone is teaching you either of those approaches, change the teacher.
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);
}
I am trying to understand char pointer in C more but one thing gets me.
Supposed I would like to pass a char pointer into a function and change the value that pointer represents. A example as followed:
int Foo (char *(&Msg1), char* Msg2, char* Msg3){
char *MsgT = (char*)malloc(sizeof(char)*60);
strcpy(MsgT,"Foo - TEST");
Msg1 = MsgT; // Copy address to pointer
strcpy(Msg2,MsgT); // Copy string to char array
strcpy(Msg3,MsgT); // Copy string to char pointer
return 0;
}
int main() {
char* Msg1; // Initial char pointer
char Msg2[10]; // Initial char array
char* Msg3 = (char*)malloc(sizeof(char) * 10); // Preallocate pointer memory
Foo(Msg1, Msg2, Msg3);
printf("Msg1: %s\n",Msg1); // Method 1
printf("Msg2: %s\n",Msg2); // Method 2
printf("Msg3: %s\n",Msg3); // Method 3
free(Msg1);
free(Msg3);
return 0;
}
In the above example, I listed all working methods I know for passing char pointer to function. The one I don't understand is Method 1.
What is the meaning of char *(&Msg1) for the first argument that is passed to the function Foo?
Also, it seems like method 2 and method3 are widely introduced by books and tutorials, and some of them even referring those methods as the most correct ways to pass arrays/pointers. I wonder that Method 1 looks very nice to me, especially when I write my API, users can easily pass a null pointer into function without preallocate memory. The only downside may be potential memory leak if users forget to free the memory block (same as method 3). Is there any reason we should prefer using Method 2 or 3 instead Method 3?
int f(char* p) is the usual way in C to pass the pointer p to the function f when p already points to the memory location that you need (usually because there is a character array already allocated there as in your Method 2 or Method 3).
int f(char** p) is the usual way in C to pass the pointer p to the function f when you want f to be able to modify the pointer p for the caller of this function. Your Method 1 is an example of this; you want f to allocate new memory and use p to tell the caller where that memory is.
int f(char*& p) is C++, not C. Since this compiles for you, we know you are using a C++ compiler.
Consider what happens when you take an argument of type int& (reference to int) :
void f(int &x) {
x++;
}
void g(int x) {
x++;
}
int main() {
int i = 5;
f(i);
assert(i == 6);
g(i);
assert(i == 6);
}
The same behaviour can be achieved by taking a pointer-to-int (int *x), and modifying it through (*x)++. The only difference in doing this is that the caller has to call f(&i), and that the caller can pass an invalid pointer to f. Thus, references are generally safer and should be preferred whenever possible.
Taking an argument of type char* (pointer-to-char) means that both the caller and the function see the same block of memory "through" that pointer. If the function modifies the memory pointed to by the char*, it will persist to the caller:
void f(char* p) {
(*p) = 'p';
p = NULL; //no efect outside the function
}
int main() {
char *s = new char[4];
strcpy(s, "die");
char *address = s; //the address which s points to
f(s);
assert(strcmp(s, "pie") == 0);
assert(s == address); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, has not changed
}
Taking an argument of type char*& ( reference-to-(pointer-to-char) ) is much the same as taking int&:
If the function modifies the memory pointed to by the pointer, the caller will see it as usual. However, if the function modifies the value of the pointer (its address), the caller will also see it.
void f(char* &p) {
(*p) = 'p';
p = NULL;
}
int main() {
char *s = new char[4];
strcpy(s, "die");
char *address = s; //the address which s points to
f(s);
assert(strcmp(address, "pie") == 0); //the block that s initially pointed to was modified
assert(s == NULL); //the 'value' of the variable s, meaning the actual addres that is pointed to by it, was changed to NULL by the function
}
Again, you could take a char** (pointer-to-pointer-to-char), and modify f to use **p = 'p'; *p = NULL, and the caller would have to call f(&s), with the same implications.
Note that you cannot pass arrays by reference, i.e. if s was defined as char s[4], the call f(s) in the second example would generate a compiler error.
Also note that this only works in C++, because C has no references, only pointers.
You would usually take char** or char*& when your function needs to return a pointer to a memory block it allocated. You see char** more often, because this practice is less common in C++ than in C, where references do not exist.
As for whether to use references or pointers, it is a highly-debated topic, as you will notice if you search google for "c++ pointer vs reference arguments".
What I am trying to do is to place a class object in the buffer and then be able to reference it correctly later.Essentially its a container class using a buffer for data storage.The best way I thought of doing so was storing the object's address in the buffer, reference it by its index, and then cast it. I see now by doing it that way can potentially leave memory leaks because the object is only living locally in this method and the address of that local object is being returned. Is there a way I can store the object into the buffer and have it correctly referenced later by invoking overloaded operator[] Foo[index]?
I have tried using the same technique with C++: Casting an Object to char* for saving/loading but static/re-interpret cast in my case are tending to change the address values when I attempt to do an address look up for the contents in the buffer.
ps. I know that using a vector would be an easier way of storing class objects but part of the restriction is that I can't use STL for data storage and have to rely on the buffer given to me.
#include <stdlib.h>
#include <assert.h>
#ifndef FOO_H_
#define FOO_H_
template <typename T>
class Foo {
char * oBuffer = NULL;
unsigned items = 0, bSize = 0;
public:
Foo(char * pBuffer, unsigned nBufferSize) :
oBuffer(pBuffer),
items(),
bSize(nBufferSize){
/*for (unsigned i =0; i < nBufferSize; i++)
oBuffer[i] = &pBuffer[i];*/
}
~Foo(){ delete[] oBuffer;}
T * Add(){ ///====== Adds an element to the container, constructs it and returns it to the caller.
assert(Capacity() > Count());
T nObj; // new object
T *nElement = &nObj; // address of new object
oBuffer += items; // incrementing pointer by item count
oBuffer = (char*) nElement; // attempt to store object address in buffer[items] location
items++; // increment items count by one
return (T*) &oBuffer;
}
T * operator [] (unsigned nIndex){ ///====== Returns the n th element of the container [0..Count -1].
return (T*) (&oBuffer[nIndex]);
}
};
#endif
Originally I was trying to do the add as follows:
T * Add(){ ///====== Adds an element to the container, constructs it and returns it to the caller.
assert(Capacity() > Count());
T *add =&(oBuffer[items++] = T{});
return add;
}
But I would come into problems when T = was a custom class object.
You have undefined behaviors in your Add function, as first you store a pointer to a local variable (with oBuffer = (char*) nElement), then with the same statement you overwrite the original pointer, which you already overwritten in the statement above, and then you return the address of the pointer (i.e. char **) but cast it as a single pointer.
Your indexing function also will not work, as nIndex is the index in the char "array" and will not be the same unless the templated type T is char.
If you want to store objects of a certain type, use std::vector.
If you want serialization for saving to file/sending over network, it won't work either for any type containing pointer, collections, files etc.