I have access to an API that returns const char *
, where it is guaranteed that the underlying string is valid all through the program, like below:
extern const char *getStr(); // an API that returns const char*
int main() {
const char **p_tmp = &( getStr() ); // HOW??
}
I would like to get the address of the underlying const char *
and use it throughout the program, however, as the returned value is of type const char *
, instead of const char *&
, getting the address of returned value gets error: lvalue required as unary '&' operand
.
Now, as I only have the access to the API returning const char *
, that is, I can neither change the function to return const char *&
nor const char **
instead. Is there any way I can still get the address of the underlying const char *
?
Conveniently asking, I did a workaround below that "persisted" the return value and use the pointers/addresses to the "persisted" const char *
, is it a good practice?
static std::vector<const char*> tmp;
static int indexInTmp = 0;
extern const char* getStr();
int main() {
tmp.emplace_back( getStr() );
const char **p_tmp = &tmp[indexInTmp++];
// ...other things
}
You are thinking too much like "C". Yes you have a "C" api, but your program will be "C++" and that means use as little raw owning pointers as possible. Also in C++ use std::string for text.
Note : if the "C" api would return a char*
(not const) you might actually have to call free on that pointer (look at the "C" API doc). By making C++ functions like this you can ensure your C++ will only solve that memory issue once.
So you should do this:
#include <string>
#include <print>
#include <stdio.h>
const char* get_string(bool condition) // your api
{
if (condition)
{
return "Hello World!";
}
else
{
return nullptr;
}
}
void set_string(const char* str) // your api
{
if (str != nullptr)
{
printf("C set_string: %s\n", str);
}
}
// Wrap you "C" calls into a C++ namespace
namespace your_api
{
std::string get_string(bool condition)
{
const char* str = ::get_string(condition);
// create a std::string by copy since
// the raw pointer from the "C" API is not guaranteed to be valid after the call
// cannot construct a std::string from nullptr directly so be safe
return std::string{str == nullptr ? std::string{} : std::string{str}};
}
void set_string(std::string_view sv)
{
// Convert std::string_view to const char* and call the C API
::set_string(sv.data());
}
} // namespace your_api
int main()
{
std::string ok_str = your_api::get_string(true);
std::string null_str = your_api::get_string(false);
std::print("ok_str: {}\n", ok_str);
std::print("null_str: {}\n", null_str);
std::string cpp_string{"Hello from C++!"};
your_api::set_string(cpp_string);
}