Лучший способ представить двумерный массив на C++ с размером, определяемым во время выполнения

В C++ я бы хотел сделать что-то вроде:

int n = get_int_from_user();

char* matrix = new char[n][n];

matrix[0][0] = 'c';
//...
matrix[n][n] = 'a';

delete [][] matrix;

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

boost :: multi_array делать это вручную будет беспорядком.
Dustin Getz 02.11.2008 03:38
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
20
1
17 520
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Для истинного двумерного массива:

int n = get_int_from_user();

char** matrix = new char*[n];
for (int i = 0; i < n; i++) {
    matrix[i] = new char[n];
}

// Operations on matrix.

for (int i = 0; i < n; i++) {
    delete [] matrix[i];
}
delete matrix;

Просто с головы до ног. Ошибки, без сомнения. Однако я думаю, что другие люди опубликовали более элегантный подход.

Обычно я делаю что-то вроде этого:

char *matrix = new char [width * height];

matrix[i + j * width] = 'c'; // same as matrix[i][j] = 'c';

delete [] matrix;

Да, это, наверное, лучший способ. Оберните доступ в функцию, и все будет хорошо.

Bernard 02.11.2008 03:19

Я считаю, что именно так и обрабатываются многомерные массивы под крышками

Kip 02.11.2008 05:19
Ответ принят как подходящий

Ручной динамический способ:

Допустим, вам нужен массив шириной * высотой, наиболее эффективный способ - просто использовать одномерный массив:

char *matrix = new char[width*height];

Чтобы удалить его:

delete[] matrix;

Чтобы получить к нему доступ:

char getArrayValue(char *matrix, int row, int col)
{
  return matrix[row + col*width];
}

Чтобы изменить это:

void setArrayValue(char *matrix, int row, int col, char val)
{
  matrix[row + col*width] = val;
}

Матрица усиления:

Рассмотрите возможность использования boost :: matrix, если у вас может быть зависимость.

Затем вы можете подключиться к библиотекам улучшить линейную алгебру.

Вот какой-то пример кода boost :: matrix:

#include <boost/numeric/ublas/matrix.hpp>
using namespace boost::numeric::ublas;
matrix<char> m (3, 3);
for (unsigned i = 0; i < m.size1 (); ++ i)
    for (unsigned j = 0; j < m.size2 (); ++ j)
        m (i, j) = 3 * i + j;

В стеке для некоторых компиляторов:

Некоторые компиляторы фактически позволяют создавать в стеке массивы с размерами, определяемыми во время выполнения. g ++ - пример такого компилятора. Однако вы не можете сделать это по умолчанию VC++.

Итак, в g ++ это действительный код:

int width = 10;
int height = 10; 
int matrix[width][height];

Дрю Холл упомянул, что эта функция C99 называется массивами переменной длины (VLA) и, вероятно, может быть включена в любом современном компиляторе.

См. Заголовок вопроса «... с размером, определенным во время выполнения». Поэтому он не может использовать стек или константу.

Jeremy Ruten 02.11.2008 03:30

Вы можете создавать массивы с определенным размером в стеке в g ++

Brian R. Bondy 02.11.2008 03:58

Это функция C99, называемая массивами переменной длины (VLA) - ее, вероятно, можно включить в любом современном компиляторе, поддерживающем C и C++.

Drew Hall 02.11.2008 04:08

Кажется, вам не хватает всего C++ (C с классами) :-). Это тот вид использования, который требует от класса его реализации.

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

  • конструктор, который при заданном n просто создаст новый массив символов n * n (например, charray).
  • функции-члены, которые получают и устанавливают значения на основе x.y, которые просто ссылаются на charray [x * n + y];
  • деструктор, который удаляет [] массив.

А как насчет std::vector< std::vector<int> > array2d;?

Стоит отметить тактико-технические характеристики. Изменение размера массива в одном направлении будет быстрым. Но доступ к элементам будет медленным из-за плохой локализации кеша (векторы могут оказаться в удаленных частях памяти). С другой стороны, если бы вы использовали непрерывное хранилище, как в большинстве других ответов, у вас было бы немного более медленное изменение размера по вертикали, немного более быстрое изменение размера по горизонтали и гораздо лучшая локализация кеша.

Stefan Monov 30.03.2010 11:20

Мне нравится подход с одномерным массивом (выбранный ответ Брайана Р. Бонди) с расширением, в котором вы обертываете элементы данных в класс, чтобы вам не нужно было отслеживать ширину отдельно:

class Matrix
{
    int width;
    int height;
    char* data;
public:
    Matrix();
    Matrix(int width, int height);
    ~Matrix();

    char getArrayValue(int row, int col);
    void setArrayValue(int row, int col, char val);
}

Реализация - это упражнение для читателя. ;)

Два возможных улучшения. Вы можете сделать его классом-шаблоном. И вы можете заменить getArrayValue и setArrayValue на operator () (int, int), возвращающий ссылку. Или, в идеале, эмуляция синтаксиса [x] [y] через прокси-класс, но я думаю, что сложно гарантировать, что прокси-класс всегда оптимизирован.

Stefan Monov 30.03.2010 11:25

Думаю, это было бы неплохо.

int n = get_int_from_user();

char **matrix=new (char*)[n];

for(int i=0;i<n;i++)
    matrix[i]=new char[n];

matrix[0][0] = 'c';
//...
matrix[n][n] = 'a';

for(int i=0;i<n;i++)
    delete []matrix;
delete []matrix;
std::vector<int> m;

Затем вызовите m.resize () во время выполнения.

int* matrix = new int[w*h];

если вы хотите сделать что-то вроде исключения Гаусса, ваша матрица должна быть

int** matrix = new int*[h];
for(size_t i(0); i < h; ++i)
    matrix[i] = new int[w];

(при исключении Гаусса нам обычно нужно обменивать одну строку на другую, поэтому лучше поменять местами указатели на строки за постоянное время, чем переставлять путем копирования за линейное время).

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