0

I try to create a char* values[] for my unittests that will be written but initialized from constants. The naive way throws a warning that ISO C++ forbids it:

char* single[1];
single[0] = "foobar";

I tried the following that obviously does not work:

std::string executable = "foobar";
std::array<char, executable.size()> data; // Error: size not known at compile time
std::copy(executable.begin(), executable.end(); data.data());

char* single[1];
single[0] = data.data();

There must be a way like:

std::array<char> data = { "foobar" };
char* single[1];
single[0] = data.data();
2
  • 2
    In C++ string literals are constant character arrays. So you have to write for example const char* single[1]; single[0] = "foobar"; Commented Mar 16, 2017 at 10:00
  • @VladfromMoscow But I need char** so I can freely manipulate the data. The constness is in the way. Commented Mar 16, 2017 at 10:01

6 Answers 6

4

I suggest you to add to_array to your toolbox. Then you can simply write

auto data = to_array("foobar");
char* single[1];
single[0] = data.data();
Sign up to request clarification or add additional context in comments.

1 Comment

This is a great find, too bad it's not standard yet.
3
std::string foo = "foobar";
std::vector<char> data(foo.data(), foo.data()+foo.size()+1u);
char* single[1];
single[0] = data.data();

How to convert a std::string to const char* or char*?

You can use some kind of transformation function if this pattern reoccurs:

template<class CharT, std::size_t N>
std::vector<CharT> literal_vector(CharT const (&a)[N])
{
    return std::vector<CharT>(&a[0], (&a[0]) + N);
}

and then

std::vector<char> lv = literal_vector("Hello");
single[0] = lv.data();

Comments

3

Even though your question has not been tagged as c++1z, it is worth mentioning that the constness restriction of the data function of std::string has been lifted in the current working draft of the Standard (N4618), which is about to be published as C++17. In [basic.string], one can find both:

const charT* data() const noexcept;
charT* data() noexcept;

Your compiler may already have support for it, possibly needing the compiler flag -std=c++1z or similar. If so, you should be able to write:

std::string executable = "foobar";
char *single[1];
single[0] = executable.data();

1 Comment

This is the minimal approach I want and hopefully will use soon.
1

Here you have tow ways, both of them are using memcpy.

  1. Using dynamic memory.
  2. Using static memory.
 

    using namespace std;

    #define MAX_BUFFER_SIZE 250
    int main()
    {
        const char* myData = "This is My Data";

        int sizeOfmydata = std::strlen(myData);;

        //1.- Dinamic Memory
        char* data1 = new char[sizeOfmydata];
        std::memcpy(data1, myData, sizeOfmydata);

        //2.- Static Memory
        char data2[MAX_BUFFER_SIZE];
        memset(data2, '\0', MAX_BUFFER_SIZE);
        std::memcpy(data2, myData, sizeOfmydata);


        delete[] data1;
        return 0;
    }

Comments

-1

You can use std::vector<std::string> to store your data, and use c_str() of std::string to parse your string to char*

5 Comments

c_str() returns const char* not char *
You can change it back like @pergy did
Which is probably unsafe and UB.
@Pixelchemist What does UB mean?
@aggsol: Undefined behaviour which essentially means: The c++ standard doesn't provide a guarantee about it. Using const_cast on the return value of c_str and manipulating the data through the resulting pointer might work... today... if you jump twice ... and if the sun is brighter than yesterday... on your compiler ...
-1

This is a bit long but it seems to do what you need. This is file foo.cpp:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdio>

int main(int argc, char* argv[])
{
    std::vector<std::string> strings = {"foobar", "barbaz"};

    char* values[strings.size()];

    for (int i = 0; i < strings.size(); ++i) {
        values[i] = new char[strings[i].size() + 1];
        std::copy(strings[i].cbegin(), strings[i].cend(), values[i]);
        values[strings[i].size()] = '\0';
    }

    for (int i = 0; i < strings.size(); ++i) {
        printf("%s\n", values[i]);
    }

    return 0;
}

Then:

$ make foo
g++     foo.cpp   -o foo
$ ./foo
foobar
barbaz

You should of course delete each of the elements of the array of char*, and maybe put the loop for copying from std::string to char* in a function and so on.

PS: auch, this solution is identical to this answer that someone already linked.... The linked other answer has more detail. Does that mean your question is a duplicate? I let experienced users decide.

3 Comments

No I want char* val[] or char** val because I need to manipulate the array and it's values.
@aggsol sorry for misunderstanding
@aggsol Now I think I did better :) at least it is easy to write all literals and then you just copy them to memory you create with new which is I am afraid unavoidable if you don't want constness

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.