2014-08-28 3 views
3

Мне часто нужно создать 2D-массив с шириной и высотой (пусть они будут n и m) неизвестны во время компиляции, обычно я пишу:int [n] [m], где n и m известны во время выполнения

vector<int> arr(n * m); 

И доступ к элементам вручную:

arr[j * m + i] 

недавно я получил сказал, что я мог бы вместо того, чтобы написать:

int arr[n][m] // n and m still only known at runtime. 

Так вот 2 questi

  1. Возможно ли такое поведение допускается стандартом C++?
  2. Как передать такой массив функции? g ++ сообщает, что arr имеет тип int (*)[n], но опять же n является динамическим и неизвестным вне функции, где он объявлен (main).
+2

1. Нет. 2. Имеет ли значение, если ответ на 1. "нет"? – juanchopanza

+7

Это нестандартное поведение (и вы можете изменить параметры компилятора, чтобы запретить нестандартное поведение).Сделайте то, что вы делаете с вектором, но просто завершите его в классе. – chris

+1

Или используйте 'vector >' – matsjoyce

ответ

5

Функция, о которой вы спрашиваете (где размеры известны только во время выполнения), является нестандартным расширением C++, но стандартным для C.99 (сделанным в необязательной функции в C.11). Эта функция называется variable-length array (VLA), а ссылка - документация для GCC.

Если вы используете GCC, то вы должны передать длину массива в качестве параметра функции.

void foo (int m, int arr[][m]) { 
    //... 
} 

Однако, кажется, есть ошибка в любом компиляторе или документации, как указано выше функция синтаксиса прототип работает только при компиляции кода C, а не C++ (как НКУ версии 4.8.2). Единственная работа вокруг я нашел использовать параметр void * и брось его ИНТ тело функции:

int foo_workaround (int m, void *x) 
{ 
    int (*arr)[m] = static_cast<int (*)[m]>(x); 
    //... 
} 

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

std::vector<std::vector<int> > arr(n, std::vector<int>(m)); 

Однако, если вы хотите один блок распределения, как вы продемонстрировали в своем собственном примере, то лучше создать класс-оболочку около vector, чтобы дать вам синтаксис типа 2-d.

template <typename T> 
class vector2d { 

    int n_; 
    int m_; 
    std::vector<T> vec_; 

    template <typename I> 
    class vector2d_ref { 
     typedef std::iterator_traits<I> TRAITS; 
     typedef typename TRAITS::value_type R_TYPE; 
     template <typename> friend class vector2d; 
     I p_; 
     vector2d_ref (I p) : p_(p) {} 
    public: 
     R_TYPE & operator [] (int j) { return *(p_+j); } 
    }; 

    typedef std::vector<T> VEC; 
    typedef vector2d_ref<typename VEC::iterator> REF; 
    typedef vector2d_ref<typename VEC::const_iterator> CREF; 

    template <typename I> 
    vector2d_ref<I> ref (I p, int i) { return p + (i * m_); } 

public: 

    vector2d (int n, int m) : n_(n), m_(m), vec_(n*m) {} 
    REF operator [] (int i) { return ref(vec_.begin(), i); } 
    CREF operator [] (int i) const { return ref(vec_.begin(), i); } 

}; 

обертка в operator[] возвращает промежуточный объект, который также перегружает operator[], чтобы позволить 2-мерный массив синтаксиса при использовании оболочки.

vector2d<int> v(n, m); 
    v[i][j] = 7; 
    std::cout << v[i][j] << '\n'; 
+0

Я использую g ++, компиляции, не соответствующие мне (используя -std = C++ 11) для следующих функций (здесь просто прототипы): int sum (int n, int [] [n] m); int sum (int n, int [n] [n] m); Причина: «использование параметра вне функции тела до] токена». Что не так? – cdkrot

+0

Вместо этого попробуйте '-std = gnu ++ 11'. – jxh

+0

Все еще не компилируется. – cdkrot

2

Почему нет std::vector из std::vector «S?

std::vector<std::vector<int> > arr(n, std::vector<int>(m)); 

Доступ элемент становится:

std::cout << "(2,1) = " << arr[2][1] << std::endl; 
+0

Это не простой 2D-массив, это массив массива. Но это решение также приемлемо. – cdkrot

+0

@cdkrot 2D-массив *** - это массив массивов ... – scohe001

+0

@Jost, если вы объявите int a [10] [10], это будет внутренне, int a [100] – cdkrot

Смежные вопросы