8

How can I initialize 2d array with a list of 1d arrays?

void main()
{
    int a[] = { 1,2,3 };
    int b[] = { 4,5,6 };
    int array[][3] = { a,b };
}
3
  • 4
    Please note that in c++ main is required to have the return type int even if you never return from it. Commented Jan 9, 2019 at 16:01
  • @FrançoisAndrieux : my visual studio does not complain about it. I am using c++17. Commented Jan 9, 2019 at 16:03
  • 2
    Visual Studio won't complain about a lot of things. The same is true about all compilers and IDEs. First because the language does not require the compiler to diagnose every kind of error and also because many platforms provide default-on extensions that are not portable as best, and non-compliant at worst. It's a fact that the forms of main defined by the language all require the return type int in c++. One thing of note about main is that any platform can define any form of main they want, including ones that return void though they are by definition not portable. Commented Jan 9, 2019 at 16:04

4 Answers 4

14

raw arrays in C++ are kind of second class citizens. They can't be assigned and they can't be copied, which means you can't use them to initialize other arrays, and their name decays into a pointer in most circumstances.

Lucky C++11 offers a solution. std::array acts like a raw array, but it doesn't have the drawbacks. You can use those instead to build a 2d array like

std::array<int, 3> foo = {1,2,3};
std::array<int, 3> bar = {3,4,5};
std::array<std::array<int, 3>, 2> baz = {foo, bar};

and if you have C++17 support you can leverage class template argument deduction to get rid of having to specify the template parameters and the code simplifies to

std::array foo = {1,2,3};
std::array bar = {3,4,5};
std::array baz = {foo, bar};

which you can see working in this live example

Sign up to request clarification or add additional context in comments.

3 Comments

It works in this case, but beware the uintuitive things that can (and occasionally have to) happen with this kind of initialization. If you didn't have foo and bar already, you'd have to write std::array<std::array<int, 3>, 2> array = { 0, 1, 2, 3, 4, 5 };, not ... = { { 0, 1, 2 }, { 3, 4, 5 } }; (the latter does not compile)!
@MaxLanghof You could also use std::array test = {std::array{1,2,3},std::array{3,4,5}}
unfortunately CTAD doesn't work (yet hopefully) through a using directive to shorten the name :(
5

Use std::array.

auto a = std::array{ 1,2,3 };
auto b = std::array{ 4,5,6 };
auto array = std::array{ a,b };

Demo

Comments

5

The way you presented - not at all... You can have:

int array[][3] = { { 1, 2, 3 }, { 4, 5, 6 } };

If you still need a and b, you could then have these as pointers:

int* a = array[0];
int* b = array[1];

or a bit closer to your original try: References to array:

int(&a)[3] = array[0];
int(&b)[3] = array[1];

This way, you could still e. g. apply sizeof to a and b...

Or the other way round: create an array of pointers

int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int* array[] = { a, b };

All these solutions presented so far have in common that both a and array[0] access exactly the same data. If you actually want to have two independent copies instead, then there's no way around copying the data from one into the other, e. g. via std::copy.

If you switch from raw array to std::array, though, you can have this kind of initialisation (with copies) directly:

std::array<int, 3> a;
std::array<int, 3> b;
std::array<std::array<int, 3> 2> array = { a, b };

Comments

3

std::array is the way to go here, but if you want to stick to the means of the language (and not the standard lib), and your combined array has the same life time as its constituents, and if the data can be shared, you can have an array of pointers to arrays and say

int a[] { 1,2,3 };
int b[] { 4,5,6 };

decltype(a) *abArr[] {&a, &b};
// equivalent to 
// int (*abArr[])[3] { &a, &b };

Note that this is not a 2-dimensional array, and its elements are not integers. But you can still range-loop through both dimensions because the pointers are true pointers to a fixed-size array (as opposed to pointers to a mere int as a result of array decay, which couldn't be range-looped).

Since the array elements are pointers it is necessary to dereference row:

for (auto const& row : abArr)
    for (auto const& e : *row)
        cout << e << " ";

Live example: http://coliru.stacked-crooked.com/a/cff8ed0e69ffb436

Comments

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.