tags:

views:

136

answers:

7

My current project requires me to fill an array based upon some other values. I know there's the shortcut:

int arr[4][4] = { {0,0,0,0} , {0,0,0,0} , {0,0,0,0} , {0,0,0,0} };

But in this case, I need to fill the array after its declaration. I currently have my code formatted like this:

int arr[4][4];
if(someothervariable == 1){
    arr = { {1,1,1,1},
            {1,2,3,4},
            {2,,3,4,5},
            {3,4,5,6} };
}

But it won't compile. Is there a way to make use of the mentioned shortcut in my case? If not, whats the best fix available? I'd appreciate a way to set it without explicitly assigning each element? ie: arr[0][0] = ...

+1  A: 

No, array initialization syntax is for array initialization. Although, you can use memset if all the values are the same byte.

The boost.assign library adds some interesting syntax for modifying/filling collections, but AFAIK it doesn't support C style arrays (only C++ and Boost containers).

Terry Mahaffey
A: 
int arr[4][4];
if (someothervariable == 1) {
     int tmp[4][4] = { {1, 1, 1, 1}, {1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6} };
     arr = tmp;
}
telaviv
Arrays are not assignable. `arr = tmp` will not compile.
AndreyT
+1  A: 

In the current version of C++ language the only way to do it is to copy it from some original

int arr[4][4];

if (someothervariable == 1)
{
  const int SOURCE[4][4] = // make it `static` if you prefer
  { 
    {1, 1, 1, 1},
    {1, 2, 3, 4},
    {2, 3, 4, 5},
    {3, 4, 5, 6} 
  };

  assert(sizeof arr == sizeof SOURCE); // static assert is more appropriate
  memcpy(&arr, &SOURCE, sizeof arr);
}

The source "constant" can be declared as static in order to avoid re-initialization, if the compiler is not smart enough to optimize it by itself.

In the future version of the language a feature similar to C's compound literals is planned, which will provide support for immediate initialization (basically what you tried to do in your original post).

AndreyT
This has a `C++` tag (not a `C` tag), so I'd prefer `std::copy()` (and expect it to fall back on `std::memcpy()` when appropriate). [Cubbi did that right](http://stackoverflow.com/questions/3010413/what-is-the-easiest-way-to-set-the-value-of-an-entire-array/3010462#3010462).
sbi
@sbi: Unfortunately array type is not assignable in C++, which is why there's no immediately legal `std::copy`-based solution. Cubbi did it wrong (formally speaking), because he reinterpreted a 2D array as an 1D array. This is formally illegal in C++ and a pedantic (debugging) implementation has all rights to crash on that code. There's no elegant solution with one `std::copy`. You have to do nested copying to copy a 2D array in a pedantically correct way.
AndreyT
@AndreyT: You do have a point there. While I cannot imagine an implementation where 2-dimensional arrays aren't contiguous, if they are, using `std::memcpy()` will be just as good.
sbi
Ha! Except when you're not using built-ins! Then, using `std::copy()` would be causing "less UB" then using `std::memcpy()` does. `:)`
sbi
A: 

If you wish to fill the array with a single value:

#include<algorithm>
#include<vector>

// ...
std::vector<int> arr;
std::fill(arr.begin(), arr.end(), VALUE);  // VALUE is an integer

If you wish to calculate the value for each element:

struct get_value {
    int operator()() const { /* calculate and return value ... */ }
};

std::generate(arr.begin(), arr.end(), get_value());
wilhelmtell
+2  A: 

How about using std::copy() ?

int arr[4][4];
if(someothervariable == 1){
        const static int a2[4][4] = { {1,1,1,1},
                                      {1,2,3,4},
                                      {2,3,4,5},
                                      {3,4,5,6} };
        std::copy(&a2[0][0], &a2[0][0]+16, &arr[0][0]);
}
Cubbi
AndreyT
Cubbi
A: 

If you are setting everything to the same value (such as zero), you may be able to get away with ...

memset (arr, 0, sizeof (arr));

Note that this is fraught with perils. You have to know your type sizes and all that jazz.

However, it appears that that will not suffice for you. If you want to fill the array with different values, I can only only think of two ways of doing this.

Method #1. (Can be a pain the butt)

arr[0][0] = 1;
...
arr[0][3] = 1;
arr[1][0] = 1;
...
arr[1][3] = 4;
arr[2][0] = 2;
...
arr[2][3] = 5;
arr[3][0] = 3;
...
arr[3][3] = 6;

Method #2. Predefine a set of arrays and switch between them using a pointer;

int  arr1[4][4] = {
        {0,0,0,0},
        {0,0,0,0},
        {0,0,0,0},
        {0,0,0,0} };
int  arr2[4][4] = {
        {1,1,1,1},
        {1,2,3,4},
        {2,,3,4,5},
        {3,4,5,6} };

int *arr[4];

Now you only have the four (4) values of *arr[] to set instead of setting everything. Of course, this really only works if your arrays will be filled with predetermined constants.

Hope this helps.

Sparky
GMan
A: 

I'm not sure if I like this solution or not, but C/C++ will give you assignment convenience if you wrap the array inside a struct with the minor cost of then having to use the struct name to get at the array:

typedef struct {
    int data[4][4];
} info_t;

info_t arr;

if (someothervariable == 1){
    static const info_t newdata = {{  // since this is static const, there generally
                                      // won't be a copy - that data will be 'baked' 
                                      // into the binary image (or at worst a
                                      // single copy will occur)
        {1,1,1,1},
        {1,2,3,4},
        {2,3,4,5},
        {3,4,5,6} 
    }};
    arr = newdata;  // easy to assign new data to the array
}

int somethingelse = arr.data[1][2]; // a tiny bit less convenient to get 
                                    //    to the array data
Michael Burr
This is C++, so the `typedef` isn't necessary. (BTW, he inconvenience could be overcome by overloading `operator[]` for `info_t`.)
sbi