I'm trying to get rid of the ISO C forbids converting a string constant to ‘char*’
warning, my code looks like the following:
char* var[] = {"abc", "def"};
// many more lines like this ...
One solution is to prepend each string literal with (char*)
however that's ugly and unmaintainable. Ideally I'd like to be able to edit these lines to say
char* var[] = array_cast<char*>({"abc", "def"});
I found a solution here for almost the same problem except it deals with std::array
instead of plain C arrays and array variables rather than initializer lists.
I want to avoid using std::array
, std::string
, const char*
, std::vector
since the functions that eventually get called accept non-const char**
.
CodePudding user response:
C string literals are constant and will be placed in the .data section and protected from being modified by the hardware. No amount of casting will fix that.
C strings (std::string
) are mutable so use those:
#include <string>
using namespace std::literals;
std::string var[] = {"abc"s, "def"s};
Although why you would want mutable strings in an array escapes me.
CodePudding user response:
"abc"
and "def"
are string literals of type const char[4]
which decays to const char*
(and not char*
) due to type decay.
So you need to add a low-level const
indicating that var
is an array of pointers to const char
(instead of pointer to char
) as shown below:
const char* var[] = {"abc", "def"};
Or better yet use std::array
or std::vector
with elements of type std::string
.
std::vector<std::string> var{"abc", "def"};
CodePudding user response:
As a possible workaround, it would be possible to use two arrays, one with std::string
objects, and one with char*
pointers to the strings in the first array:
std::array<std::string, 2> real_strings = {{ "foo", "bar" }};
char* wrap[] = { &real_strings[0][0], &real_strings[1][0] };
This can of course be used together with a vector and dynamic allocation and a loop to initialize the wrapper array, if the number of strings is not known at compile-time (or may change at run-time).
On a personal note, to me it all seems like a design flaw in the API you're using.
CodePudding user response:
I have arrived at a solution. It requires two arrays one of which needs to be cleaned up afterwards so it can surely be improved.
template<size_t N, size_t... Is>
constexpr char**
array_cast(const std::array<const char*, N>& arr, std::index_sequence<Is...>)
{
return new char*[]{const_cast<char*>(std::get<Is>(arr))...};
}
template<size_t N>
constexpr char**
array_cast(const std::array<const char*, N>& arr)
{
return array_cast(arr, std::make_index_sequence<N>());
}
const std::array var {"abc", "def"};
char** result = array_cast(var);
CodePudding user response:
You can create a modifiable 2d array of chars like this:
char var[][4] = {"abc", "def"};