Подтвердить что ты не робот

Инициализировать большой двумерный массив в С++

Я хочу иметь статический и постоянный двухмерный массив внутри класса. Массив относительно велик, но я хочу только инициализировать несколько элементов, а другие могут быть независимо от того, компилятор их инициализирует.

Например, если класс определен как:

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

и мне интересно только инициализировать элементы, помеченные знаком "7", как это сделать на тех же элементах, но с массивом большего размера, например массивом [1024] [1024]?

4b9b3361

Ответ 1

Любая часть инициализированного массива, которая находится за пределами инициализации, инициализируется равным 0. Следовательно:

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

Это означает, что все, что вам нужно инициализировать, это до последнего ненулевого:

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

Это не лучшее решение, но сохранит некоторую работу.

Ответ 2

Невозможно назначить массив int для const после его инициализации. Итак, вам придется script его:

И включите файл следующим образом:

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

Ответ 3

Кстати, через пару часов после прочтения вашего вопроса я столкнулся с возможным решением, ища что-то еще в книге "C - A Reference Manual" 5th ed., Harbison/Steele (кстати, это фантастическая ссылка на C).

Согласно книге,

C99 позволяет вам указать компоненты агрегата (структуры, объединения или массива), которые будут инициализированы в списке инициализаторов.

... и он дает пример:

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

Таким образом, в зависимости от соответствия вашего компилятора и размера ненулевых элементов в вашем массиве вы можете использовать этот синтаксис для эффективного создания вашей матрицы. Тем не менее, книга не дает примера для 2D-массивов. К сожалению, я не смог проверить эту идею, поскольку MSVС++ 2005, похоже, не поддерживает C99.

Ответ 4

Когда я это делаю, я использую метод для чтения данных. Как правило, это выглядит так:

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

Ответ 5

Вы можете получить доступ к массиву только через функции доступа/макросы и упорядочить внутреннее хранилище, чтобы сначала была инициализированная часть.

Ответ 6

Решение заключалось бы в том, чтобы спрятать не-const-массив где-нибудь, загрузить его из файла или ресурса, а затем использовать константную ссылку для доступа к ней. То есть

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

Он будет (IMO) более читабельным, чем script -генерированный огромный массив.

Вы можете сделать то же самое с классом, который действует как 2D-массив (достаточно простой для записи). Опять же - где-то есть неконстантный объект и используйте ссылку const для доступа к данным. Было бы легко сделать non-const массив полностью невидимым за пределами только одного cpp.

Другой способ сделать это - создать массив, используя script. Если вы считаете, что большие массивы уродливы, поместите всю вещь в *.h файл (убедитесь, что он включен только в один файл *.cpp), поэтому он не пугает людей. Компилятору все равно, что вы пишете в коде, если он синтаксически корректен.

Я не думаю, что есть другие варианты.

Ответ 7

Это занимает всего четыре строки, используя 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);

Ответ 8

Могу ли я задать вопрос, связанный с этой темой? На самом деле мне нужно кодировать 2-мерный массив, где число строк равно 339. Я пытался это кодировать, но я думаю, что количество строк ограничено 59. Как я могу определить свой массив?

Ответ 9

установить программное обеспечение R, бесплатно! то функция вызова, определенная ниже, с помощью

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

если данные являются вашей матрицей, тогда вы закончили


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