tags:

views:

164

answers:

6

I want to have static and constant two dimensional array inside a class. The array is relatively large, but I only want to initialize a few elements and others may be whatever compiler initializes them to.

For example, if a class is defined like:

class A {
public:
  static int const test[10][10];
};

int const A::test[10][10] = {
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0},
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0},
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0},
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

and I am interested only to initialize the elements marked with '7', how do I do this on the same elements, but with array of larger size, like array[1024][1024]?

A: 

You could access the array only through accessor functions/macros and arrange the internal storage so, that the initialzed part goes first.

Peter G.
+3  A: 

Any part of an array which is initialized, that is beyond the initialiaztion, is initialized to 0. Hence:

int const A::test[10][10];    // uninitialized

int const A::test[10][10] = { 0 }; // all elements initialized to 0.

int const A::test[10][10] = {1,2}; // test[0][0] ==1, test[0][1]==2, rest==0

That means all you have to initialize is up to the last non-zero:

int const A::test[10][10] = { 
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0},  
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
  {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0}, 
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0}, 
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0}, 
  {0, 0, 0, 7, 7, 7, 7, 0, 0, 0}
};

It's not the best solution, but is saves some work.

James Curran
Also, for we don't need to write elements that don't interest us, like: int const A::test[10][10] = { {}, {}, {}, {0, 0, 0, 7, 7, 7, 7}, {0, 0, 0, 7, 7, 7, 7}, {0, 0, 0, 7, 7, 7, 7}, {0, 0, 0, 7, 7, 7, 7}}
Matthew Murdock
A: 

A solution would be to hide non-const array somewhere, load it from file or resource, and then use const reference to access it. I.e.

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

typedef int Array[1024][1024];

namespace DontTouch{
    Array arr;
    void initArray(){
        for (int i = 0; i < 1024; i++)
            for (int j = 0; j < 1024; j++)
                arr[i][j] = rand() & 0xff;
    }
}

const Array &arr = DontTouch::arr;

int main(int argc, char** argv){
    DontTouch::initArray();

    //arr[4][4] = 0;//compiler error            
    for (int i = 0; i < 1024; i++){
        for (int j = 0; j < 1024; j++)
            printf(" 0x%02x", arr[i][j]);
        printf("\n");
    }

    return 0;
}

It will be (IMO) more readable than script-generated huge array.

You can do same thing with class that acts like 2D array (easy enough to write). Again - have non-const object somewhere, and use const reference to access the data. It should be easy to make non-const array completely invisibile outside of just one cpp.

Another way to do that is to generate array using script. If you think that big arrays are ugly, put entire thing into *.h file (make sure it is included in only one *.cpp file), so it won't scare people away. Compiler doesn't care what you write in your code as long as it is syntactically correct.

I don't think there are any other options.

SigTerm
Thanks, but here user needs to call DontTouch::initArray(), and I would like that this array is initialized automatically. Also, I want array to be static, const class member... Seems that only solution is the big generated array...
Matthew Murdock
Matthew Murdock: "and I would like that this array is initialized automatically" make a class that initializes array from within construcor and put one static instance of that class somewhere. You'll get automatic initialization.
SigTerm
+3  A: 

There is no way to assign an int to const array after it's been initialized. So you will have to script it up:

And include your file this way:

class A {
public:
    static const int test[10][10];
};

const int A::test[10][10] = {
#include "data.inc" // points to the file generated by script.
};
C Johnson
A: 

When I do this, I use a method to read in data. Generically, it looks like:

extern void ReadElements(string sFile, Matrix a)
{
    int x;
    int y;
    double value;

    ifstream myInFile;

    myInFile.open(sFile, ifstream::in);
    while(!myInFile.eof())
    {
        myInFile >> x >> y >> value;
        a[x][y] = value;
    }

    myInFile.close();
    return;
}
Jess
A: 

Coincidentally, a couple of hours after reading your question, I bumped into a possible solution while looking for something else in the book "C - A Reference Manual" 5th ed., Harbison/Steele (this is a fantastic C reference, by the way).

According to the book,

C99 allows you to name the components of an aggregate (structs, union or array) to be initialized within an initializer list.

... and it gives an example:

int a1[5] = { [2]=100, [1]=3 }; /* eqv. to {0, 3, 100, 0, 0} */

So, depending on the compliance of your compiler and on the size of the non-zero elements in your array, you may be able to use this syntax to init your matrix efficiently. That said, the book doesn't give an example for 2D arrays. Unfortunately, I couldn't test this idea since MSVC++ 2005 doesn't seem to support C99.

ysap
GCC supports this only in C, not C++.
slacker
ysap, thanks but I only made it work with C and gcc as a compiler. In Visual Studio, it doesn't work...
Matthew Murdock