Search code examples
c++arraysvariable-assignmentassignvariable-declaration

Splitting declaration and assignment with string array in C++


There is probably a really simple solution to this, but I can't seem to figure it out. I can find countless examples of how to create a string array in C++, but I can't find one that shows how to make the assignment separate.

I currently have a declaration with assignment that looks something like this:

static const char *desc[3] = { "apple", "banana", "orange" };

What I would like to do is split the declaration and assignment to separate statements. The declaration:

static const char *desc[3];

...but I can't seem to figure out how to do the assignment. I have tried the following:

desc = { "apple", "banana", "orange" }; // Expression must have a modifiable lvalue. error: assigning to an array from an initializer list
*desc = { "apple", "banana", "orange" }; // Too many initializer values. error: cannot convert '<brace-enclosed initializer list>' to 'const char*' in assignment
desc[3] = { "apple", "banana", "orange" }; // Too many initializer values. error: cannot convert '<brace-enclosed initializer list>' to 'const char*' in assignment
*desc[3] = { "apple", "banana", "orange" }; // Expression must have a modifiable lvalue. error: assignment of read-only location '* desc[3]'

Solution

  • Your first example allocates the array on the stack, which is only possible because the compiler knows the size (since all strings are fixed length and provided during declaration).

    When you separate declaration and initialization, your compiler has no way of knowing how much memory to allocate on the stack, so you need to change your type into a pointer (which has a fixed size, no matter what it points to):

    static const char** desc;
    

    and then use new to allocate enough memory for the array:

    desc = new const char*[3]{ "apple", "banana", "orange" };
    

    However that means that you now also must delete[] the array pointed to by desc, as otherwise you get a memory leak.

    Much better would be to use modern container types like std::vector and std::string:

    static std::vector<std::string> desc;
    

    and then

    desc.push_back("apple");
    desc.push_back("banana");
    desc.push_back("orange");
    

    These classes take care of all the nasty memory management for you under the hood.


    Another alternative, if you really want a raw array, and don't want to rely on new[] and delete[]is to declare a fixed size array with enough space for your strings like so:

    static const char desc[3][128];
    

    and then later copy the string values into that block of memory:

    std::strcpy(desc[0], "apple");
    std::strcpy(desc[1], "banana");
    std::strcpy(desc[2], "orange");
    

    However I really don't recommend doing this, as you risk bugs in the long run when you add or remove strings, or change their lengths etc.