2010-08-11 38 views
16

Quiero tener estática y constante matriz bidimensional dentro de una clase. La matriz es relativamente grande, pero solo quiero inicializar algunos elementos y otros pueden ser cualquier compilador que los inicialice.Inicializar una gran matriz bidimensional en C++

Por ejemplo, si una clase se define como:

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} 
}; 

y estoy interesado solamente para inicializar los elementos marcados con '7', ¿cómo puedo hacer esto en los mismos elementos, pero con gran variedad de tamaño más grande, como la matriz [1024] [1024]?

+1

Err ... parece que ya tiene la solución correcta. –

+0

¿Qué tan importante es que sus datos sean const? –

+1

@Billy: Pero le llevará 789 años codificar una matriz de 1024 x 1024. –

Respuesta

26

Cualquier parte de una matriz que es inicializado, es decir más allá de la inicialización, se inicializa a 0. Por lo tanto:

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 

Eso significa que todo lo que tiene para inicializar es hasta el último distinto de cero:

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} 
}; 

No es la mejor solución, pero ahorrará trabajo.

+3

Además, para no tener que escribir elementos que no nos interesan, como: 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}} –

+0

@Matthew las listas de inicializadores vacías son una extensión de GNU. – a3f

0

Puede acceder a la matriz solo a través de las funciones de acceso/macros y organizar el almacenamiento interno para que la parte inicializada vaya primero.

0

Una solución sería ocultar una matriz sin const en algún lugar, cargarla desde un archivo o recurso, y luego utilizar la referencia constante para acceder a ella. Es decir.

#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; 
} 

Será (IMO) más legible que la gran matriz generada por script.

Puede hacer lo mismo con la clase que actúa como matriz 2D (lo suficientemente fácil de escribir). Nuevamente, tenga un objeto no const en algún lugar, y use const reference para acceder a los datos. Debería ser fácil hacer que la matriz sin const sea completamente invisible fuera de solo una cpp.

Otra forma de hacerlo es generar una matriz mediante script. Si crees que las matrices grandes son feas, coloca todo en el archivo * .h (asegúrate de que esté incluido en un solo archivo * .cpp), para que no asuste a las personas. Al compilador no le importa lo que escriba en su código, siempre que sea sintácticamente correcto.

No creo que haya otras opciones.

+0

Gracias, pero aquí el usuario necesita llamar a DontTouch :: initArray(), y me gustaría que esta matriz se inicialice automáticamente. Además, quiero que la matriz sea estática, miembro de la clase const ... Parece que la única solución es la gran matriz generada ... –

+0

Matthew Murdock: "y me gustaría que esta matriz se inicialice automáticamente" crear una clase que inicialice la matriz desde dentro de construcor y coloque una instancia estática de esa clase en alguna parte. Obtendrá la inicialización automática. – SigTerm

7

No hay forma de asignar una matriz int a const una vez que se ha inicializado. Por lo que tendrá a la escritura para arriba:

E incluya el archivo de esta manera:

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. 
}; 
+0

Esta es una solución válida y bastante directa (especialmente cuando se consideran scripts fuera de línea para generar el archivo de cabecera). Sin embargo, puede ser problemático cuando se trata de un sistema integrado con memoria ajustada. Por algún motivo que no me queda claro, en todas las instancias del compilador que examiné, la inicialización de las variables se realiza en tiempo de ejecución, en lugar de en tiempo de carga, lo que significa que la matriz de valores del inicializador ocupará espacio adicional, en -top del espacio asignado por la variable de la matriz real en sí. – ysap

1

Cuando hago esto, yo uso un método para leer los datos. De forma genérica, que parece:

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; 
} 
+0

Pero, ¿funcionará para 'const' array? – ysap

3

Coincidentemente, un par de horas después de leer su pregunta, me encontré con una posible solución en la búsqueda de algo más en el libro "C - A Reference Manual" 5th ed., Harbison/Steele (esta es una fantástica de referencia C, por cierto)

Según el libro,

C99 le permite nombrar los componentes de un agregado (estructuras, unión o matriz) para ser inicializadas dentro de una lista de inicialización.

... y da un ejemplo:

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

Así, en función del cumplimiento de su compilador y del tamaño de los elementos no nulos en la matriz, que puede ser capaz de use esta sintaxis para iniciar su matriz de manera eficiente. Dicho esto, el libro no da un ejemplo para matrices 2D. Desafortunadamente, no pude probar esta idea ya que MSVC++ 2005 no parece ser compatible con C99.

+0

GCC admite esto solo en C, no en C++. – slacker

+0

ysap, gracias pero solo lo hice funcionar con C y gcc como compilador. En Visual Studio, no funciona ... –

-5

instalar el software R, ¡es gratis! entonces llamada a la función se define a continuación con

writetable(data,"test","myfile.h")

si los datos es su matriz entonces ya está


writetable<-function(data,varname="test",file="myFile.hpp"){ 
    cat('const static double CONST_array_',varname," [][] = { \n \t\t\t\t {",file=file,append=TRUE,sep='') 
    for (j in 1:(dim(data)[2]-1)){ 
    for (i in 1:(dim(data)[1]-1)){ 
     cat(data[i,j],',',file=file,append=TRUE) 
    } 
    cat(data[dim(data)[1],j],'},\n \t\t\t\t\t{',file=file,append=TRUE) 
    } 
    for (i in 1:(dim(data)[1]-1)){ 
    cat(data[i,dim(data)[2]],',',file=file,append=TRUE) 
    } 
    cat(data[dim(data)[1],dim(data)[2]],'}\n }; \n',file=file,append=TRUE) 
} 
0

Sólo se necesitan cuatro líneas mediante el uso de std::fill_n

using std::fill_n; 
using std::begin; 

fill_n(begin(test[3])+3, 4, 7); 
fill_n(begin(test[4])+3, 4, 7); 
fill_n(begin(test[5])+3, 4, 7); 
fill_n(begin(test[6])+3, 4, 7); 
+0

no funciona en 'const'. – syockit

Cuestiones relacionadas