C++ Возврат и вставка объекта 2D-массива

Я пытаюсь вернуть элемент данных массива из одного меньшего объекта 2D-массива и пытаюсь вставить массив в более крупный объект 2D-массива. Но пытаясь это сделать, я столкнулся с двумя проблемами.

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

Так выглядит мой элемент данных 2D-массива

private:
int pieceArray[4][4];
// 2D Smaller Array

и я хочу вернуть этот массив в функцию, но это вызывает ошибку компилятора:

int Piece::returnPiece()
{
    return pieceArray; //not vaild
    // return the 2D array name
}

Я устал использовать этот тип возврата, и он сработал:

int Piece::returnPiece()
{
    return pieceArray[4][4];
}

Но я не уверен, что это то, что я хочу, поскольку я хочу вернуть массив и все его содержимое.

Другая проблема - это функция InsertArray (), где я бы поместил функцию returnPiece () в аргумент InsertArray ().

Проблема с InsertArray () - это аргумент, вот код для него:

void Grid::InsertArray( int arr[4][4] ) //Compiler accepts, but does not work
{
    for(int i = 0; i &lt x_ROWS ; ++i)
    {
         for (int j = 0; j &lt y_COLUMNS ; ++j)
         {
             squares[i][j] = arr[i][j];
         }
    }
}

Проблема в том, что он не принимает мой returnPiece (), и если я удалю «[4] [4]», мой компилятор не примет.

В основном все это синтаксические ошибки, но как мне решить эти проблемы?

  1. Возврат целого массива в returnPiece ()
  2. Правильный синтаксис аргумента в InsertArray ()
  3. Аргумент InsertArray (), принимающий returnPiece ()

Это 3 основные проблемы, с которыми мне нужна помощь, и у меня возникла та же проблема, когда я пытаюсь использовать метод указателя указателя. Кто-нибудь знает, как решить эти 3 проблемы?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
6 014
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Похоже, вам нужно больше узнать об указателях в C++ и о передаче по ссылке или передаче по значению.

Ваш метод returnPiece определяется как возвращающий значение одной ячейки. Учитывая индекс (например, [4] [4]), вы возвращаете копию содержимого этой ячейки, поэтому вы не сможете его изменить, или, вернее, изменение его приведет к изменению копии.

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

Вот как бы я это сделал:

class Array {
  public:

    Array() {
      for (int i = 0; i < 4; ++i)
      {
         for (int j = 0; j < 4; ++j)
         {
            (*this)(i, j) = 0;
         }
      }
    }


    int &operator()(int i, int j)
    {
      return pieceArray[i][j];
    }

  private:
    int pieceArray[4][4];
};

Затем вы можете сделать что-то вроде:

  Array x; // create 4x4 array
  x(1, 2) = 3; // modify element

Более естественно, не следует ли поменять местами i и j? (И, возможно, вместо этого используйте x и y для удобства чтения.) Кроме того, я думаю, что конструктор копирования в порядке ...

strager 31.12.2008 10:21

i и j позиционны, поэтому вы можете использовать любой порядок, который хотите. Было бы неплохо создать конструктор копирования.

Juan 31.12.2008 10:27
Ответ принят как подходящий

Передавая свой массив, вы должны решить, хотите ли вы сделать копию массива или просто хотите вернуть указатель на массив. Для возврата массивов вы не можете (легко) вернуть копию - вы можете вернуть только указатель (или ссылку в C++). Например:

// Piece::returnPiece is a function taking no arguments and returning a pointer to a
// 4x4 array of integers
int (*Piece::returnPiece(void))[4][4]
{
    // return pointer to the array
    return &pieceArray;
}

Чтобы использовать его, назовите его так:

int (*arrayPtr)[4][4] = myPiece->returnPiece();
int cell = (*arrayPtr)[i][j];  // cell now stores the contents of the (i,j)th element

Обратите внимание на сходство между объявлением типа и его использованием - круглые скобки, оператор разыменования * и квадратные скобки находятся в одних и тех же местах.

Ваше объявление для Grid::InsertArray верное - он принимает один аргумент, который представляет собой массив целых чисел 4x4. Это вызов по значению: всякий раз, когда вы вызываете его, вы делаете копию своего массива 4x4, поэтому любые вносимые вами изменения не отражаются в переданном массиве. Если вы вместо этого хотите использовать вызов по ссылке, вы можете вместо этого передайте указатель на массив:

// InsertArray takes one argument which is a pointer to a 4x4 array of integers
void Grid::InsertArray(int (*arr)[4][4])
{
     for(int i = 0; i < x_ROWS; i++)
     {
         for(int j = 0; j < y_COLUMNS ; j++)
             squares[i][j] = (*arr)[i][j];
     }
}

Эти объявления типов с указателями на многомерные массивы могут быстро запутать. Рекомендую сделать для него typedef вот так:

// Declare IntArray4x4Ptr to be a pointer to a 4x4 array of ints
typedef int (*IntArray4x4Ptr)[4][4];

Затем вы можете объявить свои функции более читаемыми:

IntArray4x4Ptr Piece::returnPiece(void) { ... }
void Grid::InsertArray(IntArray4x4Ptr arr) { ... }

Вы также можете использовать программу cdecl, чтобы помочь расшифровать сложные типы C / C++.

Ух ты. Я понятия не имел, что вы можете вернуть 2d-массив. K&R, кажется, не против. Мне пришлось изменить объявление на: int (* returnPiece ()) [4] {return pieceArray; }

Juan 31.12.2008 10:43

Да. если вы хотите, чтобы массив распался, вы можете вернуть "pieceArray" вместо его адреса. будет возвращен указатель на его первый элемент, который имеет тип int (*) [4]. но обратная сторона - вы теряете размер внешнего измерения. я думаю, что подход Адама лучше ...

Johannes Schaub - litb 31.12.2008 12:42

... если только внешний размер не может иметь произвольный размер. но кажется, что его размер всегда равен 4. Преимущество возврата распавшегося массива заключается в том, что у вас есть естественный синтаксис iindex возвращаемого объекта thingy: foo () [4] [4], а не (* foo ()) [4] [ 4]. Принимая во внимание и то, и другое, я бы все равно предпочел Адама.

Johannes Schaub - litb 31.12.2008 12:44

Нет, его исходный Grid :: InsertArray (int arr [4] [4]) является вызовом по ссылке. В памяти есть только один массив - pieceArray, и он является общим. Ценности можно менять из-под вас. Для Call-by-Value (копирование) ... Лучший чит со структурой. (Я выложу отдельно.)

Mr.Ree 01.01.2009 08:56

Беда с Адама РозенфилдаarrayPtr в том, что Piece :: pieceArray может вылететь из-под вас. (Копирование по ссылке vs Копирование по значению.)

Копирование по значению неэффективно. Но если вы действительно хотите это сделать, просто обманите:

struct FOO { int  piece [4][4]; };

FOO Piece::returnPiece()
{
  FOO f;
  memcpy( f.piece, pieceArray, sizeof(pieceArray) );
  return f;
}

void Grid::InsertArray( const FOO & theFoo )
{
  // use theFoo.piece[i][j]
}

Конечно, лучшим, более объектно-ориентированным решением было бы создание returnPiece () и возврат объекта Кусок или Множество. (Как предложил Хуан ...)

общий подход - шаблон <typename T> struct wrap {T t; wrap (T const & t) {memcpy (this-> t, t, sizeof t); }}; шаблон <typename T> wrap <T> make_wrap (T const & t) {return wrap <T> (t); } затем верните make_wrap (pieceArray) и примите wrap <int [4] [4]> в методе InsertArray.

Johannes Schaub - litb 01.01.2009 09:09

litb: Вы подняли хороший вопрос. Но зачем обобщать кладж для преодоления неспособности C / C++ копировать массивы? make_wrap () не требуется. Остерегайтесь распространять использование memcpy () на типы, содержащие указатели. Учитывая навыки OP с C++, разумно ли увеличивать сложность кодирования с помощью шаблонов?

Mr.Ree 02.01.2009 10:20

Другие вопросы по теме