Как передать массив конструктору? - PullRequest
15 голосов
/ 24 февраля 2012

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

Вот упрощенная версия того, над чем я работаю:

#include <iostream>

class board
{
    public:
        int state[64];
        board(int arr[])
        {
            *state = *arr;
        }
        void print();
};

void board::print()
{
    for (int y=0; y<8; y++)
    {
        for (int x=0; x<8; x++)
            std::cout << state[x + y*8] << " ";
        std::cout << "\n";
    }
}

int main()
{
    int test[64] = {
        0, 1, 2, 3, 4, 5, 6, 7,
        1, 2, 3, 4, 5, 6, 7, 8,
        2, 3, 4, 5, 6, 7, 8, 9,
        3, 4, 5, 6, 7, 8, 9,10,
        4, 5, 6, 7, 8, 9,10,11,
        5, 6, 7, 8, 9,10,11,12,
        6, 7, 8, 9,10,11,12,13,
        7, 8, 9,10,11,12,13,14 };

    board b(test);
    b.print();

    std::cin.get();
    return 0;
}

Может кто-нибудь объяснить, почему это не работает и как правильно передать массив? Кроме того, я не хочу копировать массив. (И действительно ли мне нужно отступать каждую строку на 4 пробела для кода? Это довольно утомительно.)

Ответы [ 6 ]

9 голосов
/ 24 февраля 2012

В этом случае лучше всего использовать ссылку на массив:

class board
{
    int (&state)[64];

public:
    board(int (&arr)[64]) 
        : state(arr)
    {}

    // initialize use a pointer to an array
    board(int (*p)[64]) 
        : state(*p)
    {}


    void print();
};

Пара преимуществ - нет копирования массива, и компилятор обеспечит передачу массива правильного размера.

Недостатки в том, что массив, с которым вы инициализируете объект board, должен жить как минимум столько времени, сколько объект и любые изменения, сделанные в массиве вне объекта, «отражаются» в состоянии объекта. но эти недостатки возникают, если вы также используете указатель на исходный массив (в основном, только копирование массива устранит эти недостатки).

Еще одним недостатком является то, что вы не можете создать объект, используя указатель на элемент массива (то есть то, на что параметры функции массива "затухают", если размер массива не указан в параметре декларация). Например, если массив передается через параметр функции, который действительно является указателем, и вы хотите, чтобы эта функция могла создавать объект board со ссылкой на этот массив.

5 голосов
/ 24 февраля 2012

Попытка передать массив функции приводит к передаче указателя на первый элемент массива.

Вы не можете назначать массивы, а принятие параметра типа T[] такое же, как T*. Так

*state = *arr;

Разыменовывает указатели на state и arr и присваивает первый элемент arr первому элементу state.

Если вы хотите скопировать значения из одного массива в другой, вы можете использовать std::copy:

std::copy(arr, arr + 64, state); // this assumes that the array size will
                                 // ALWAYS be 64

В качестве альтернативы вы должны посмотреть на std::array<int>, который ведет себя точно так же, как вы предполагали, что массивы ведут себя:

#include <array>
#include <algorithm>
#include <iostream> 

class board
{
    public:
        std::array<int, 64> state;

        board(const std::array<int, 64> arr) // or initialiser list : state(arr)
        {
            state = arr; // we can assign std::arrays
        }
        void print();
};

void board::print()
{
    for (int y=0; y<8; y++)
    {
        for (int x=0; x<8; x++)
            std::cout << state[x + y*8] << " ";
        std::cout << "\n";
    }
}

int main()
{
    // using this array to initialise the std::array 'test' below
    int arr[] = {
        0, 1, 2, 3, 4, 5, 6, 7,
        1, 2, 3, 4, 5, 6, 7, 8,
        2, 3, 4, 5, 6, 7, 8, 9,
        3, 4, 5, 6, 7, 8, 9,10,
        4, 5, 6, 7, 8, 9,10,11,
        5, 6, 7, 8, 9,10,11,12,
        6, 7, 8, 9,10,11,12,13,
        7, 8, 9,10,11,12,13,14 };

    std::array<int, 64> test(std::begin(arr), std::end(arr));

    board b(test);
    b.print();

    std::cin.get();
    return 0;
}
1 голос
/ 24 февраля 2012
#include <iostream>

class board
{
    public:
        int * state;    //changed here, you can also use **state
        board(int *arr)               //changed here
        {
          state = arr;
        }
        void print();
};

void board::print()
{
    for (int y=0; y<8; y++)
    {
        for (int x=0; x<8; x++)
            std::cout << *(state + x + y*8) << " ";   //changed here
        std::cout << "\n";
    }
}

int main()
{
    int test[64] = {
        0, 1, 2, 3, 4, 5, 6, 7,
        1, 2, 3, 4, 5, 6, 7, 8,
        2, 3, 4, 5, 6, 7, 8, 9,
        3, 4, 5, 6, 7, 8, 9,10,
        4, 5, 6, 7, 8, 9,10,11,
        5, 6, 7, 8, 9,10,11,12,
        6, 7, 8, 9,10,11,12,13,
        7, 8, 9,10,11,12,13,14 };

    board b(test);
    b.print();

    std::cin.get();
    return 0;
}

или вы можете использовать его как:

class board
{
    public:
        int state[64];
        board(int arr[])
        {
            for(int i=0;i<64;++i)
               state[i] = arr[i];
        }
        void print();
};

РЕДАКТИРОВАТЬ 1: стабильное решение

class board
    {
        public:
            int * state;    //changed here, you can also use **state
            board(int *arr)               //changed here
            {
              state = new int[64];
              for(int i=0;i<64;++i)
                   state[i] = arr[i];
            }
            void print();
    };
0 голосов
/ 24 февраля 2012

* arr дает значение, которое хранится в arr [0]. В c ++ имя массива является указателем на первый элемент в массиве.

Поэтому, когда вы делаете * state = * arr, вы сохраняете значение в arr [0] в состоянии переменной.

Теперь, если вы хотите передать массив без явного копирования каждого элемента, я предлагаю вам создать еще один массив того же размера в методе, который вы вызываете, а затем передать имя массива из вызывающей стороны, по существу:

methodWhereArrayisPassed(int *arrayName)
{
    int arrCopy[64];
    arrCopy = arrayName;

// Do more stuff here
}

methodWhichPassesArray()
{
    // do stuff here
    int arr[] = {
       0, 1, 2, 3, 4, 5, 6, 7,
       1, 2, 3, 4, 5, 6, 7, 8,
       2, 3, 4, 5, 6, 7, 8, 9,
       3, 4, 5, 6, 7, 8, 9,10,
       4, 5, 6, 7, 8, 9,10,11,
       5, 6, 7, 8, 9,10,11,12,
       6, 7, 8, 9,10,11,12,13,
       7, 8, 9,10,11,12,13,14 };

methodWhereArrayisPassed(arr);

// do stuff here
}
0 голосов
/ 24 февраля 2012

Имя массива - это адрес первого элемента в нем.

Следовательно, строка *state = *arr установит state[0] в arr[0].

Поскольку сейчас выопределили state как int state[64];, state - это const pointer типа int, адрес которого нельзя изменить.

Вы можете изменить его на int *state; и тогда state = arr будет работать.

0 голосов
/ 24 февраля 2012

*state = *arr; использует разыменование, которое возвращает значение по адресу указателя.

Это то же самое, что state[0] = *arr;, поскольку *arr является int.

См. эту статью для получения информации об указателях.См. Раздел почтения.

Чтобы решить эту проблему, вы хотите сделать это:

for (int i = 0; i < 64; i++) state[i] = arr[i]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...