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();
aggsol
  • 2,343
  • 1
  • 32
  • 49
  • 2
    In C++ string literals are constant character arrays. So you have to write for example const char* single[1]; single[0] = "foobar"; – Vlad from Moscow Mar 16 '17 at 10:00
  • @VladfromMoscow But I need `char**` so I can freely manipulate the data. The constness is in the way. – aggsol Mar 16 '17 at 10:01

6 Answers6

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();
cpplearner
  • 13,776
  • 2
  • 47
  • 72
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();
Community
  • 1
  • 1
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
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();
metalfox
  • 6,301
  • 1
  • 21
  • 43
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;
    }

Jorge Omar Medra
  • 978
  • 1
  • 9
  • 19
-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.

Community
  • 1
  • 1
  • No I want `char* val[]` or `char** val` because I need to manipulate the array and it's values. – aggsol Mar 16 '17 at 10:03
  • @aggsol sorry for misunderstanding –  Mar 16 '17 at 10:03
  • @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 `const`ness –  Mar 16 '17 at 10:22
-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*

OrMiz
  • 265
  • 2
  • 11
  • `c_str()` returns `const char*` not `char *` – aggsol Mar 16 '17 at 10:05
  • You can change it back like @pergy did – OrMiz Mar 16 '17 at 10:08
  • Which is probably unsafe and UB. – Pixelchemist Mar 16 '17 at 10:23
  • @Pixelchemist What does UB mean? – aggsol Mar 16 '17 at 10:28
  • @aggsol: [Undefined behaviour](http://en.cppreference.com/w/cpp/language/ub) 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 ... – Pixelchemist Mar 16 '17 at 10:29