如何创建用户指定值的二维数组?

时间:2021-10-19 13:35:45

How would I declare a two dimensional array of size n by n which the user gives?
For example, why would this work:

我如何声明用户给出的大小为n的二维数组?例如,为什么这会起作用:

int n;
cin >> n;
int *array = new int[n];
//no errors

but this would not:

但这不会:

int n;
cin >> n;
int *array = new int[n][n];
// these errors:
//error: array size in new-expression must be constant
//error: the value of 'n' is not usable in a constant expression
//note: 'int n' is not const

Is it possible to have a two dimensional array of row and column size n or would you have to use a vector?
Thanks!

是否可以使用行和列大小为n的二维数组,或者您是否必须使用向量?谢谢!

5 个解决方案

#1


2  

Do it with a vector, like this:

用矢量做,像这样:

int n;
cin >> n;
auto matrix = std::vector<std::vector<int>>(n, std::vector<int>(n));

https://wandbox.org/permlink/zsOiUTvCbxAGmK6d


There is also a std::valarray template which is similar functionality as std::vector, but has interesting extra functionality, which can be useful in case of matrix.

https://wandbox.org/permlink/9Vq141QpEWcWoUxM

#2


1  

To create a multidimensional array, you would have to write this:

要创建多维数组,您必须编写以下内容:

int n;
cin >> n;
int **array = new int*[n];
for (int i = 0; i < n; i++) {
    array[i] = new int[n];
}

And don't forget to delete it:

别忘了删除它:

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

But current c++ best practice is to never allocate or deallocate memory in application code, meaning you should use a std::vector or some other container class.

但是当前的c ++最佳实践是永远不要在应用程序代码中分配或释放内存,这意味着你应该使用std :: vector或其他一些容器类。

#3


1  

This answer differs in two points from most of the other answers:

这个答案与其他大多数答案的不同点有两点:

  • no raw pointer or memory allocation
  • 没有原始指针或内存分配

  • use a single contiguous (linear) block of memory
  • 使用单个连续(线性)内存块

A common approach is using a single linear block of memory and storing the elements row after row or column after column (Row- or column-major order). Let us generalize a bit and say you want a 2D quantity of type T with the extents N0 and N1. Then you can obtain the required memory by

一种常见的方法是使用单个线性内存块并在列之后的行或列之后逐行存储元素(行或列主要顺序)。让我们概括一下,并说你想要一个带有范围N0和N1的类型T的2D数量。然后你可以通过获得所需的内存

std::vector<T> my_memory(N0*N1, T{});

Using a vector instead of a raw pointer has several advantages. For example, you can not forget to free the memory because the deconstructor cares about that automatically (RAII idiom). Another advantage is that the constructor called above fills the vector with copies of default-constructed T (instead of leaving the memory uninitialized).

使用向量而不是原始指针有几个优点。例如,你不能忘记释放内存,因为解构器会自动关注它(RAII惯用法)。另一个优点是上面调用的构造函数使用默认构造的T的副本填充向量(而不是使内存保持未初始化)。

Next, you can access the linear memory by using vector's member operator[] (or the member function at if you want bound checks). You probably want to use two indices n0 and n1 in the intervals [0, N0) and [0, N1), but the memory is linear and requires a single index. Hence you can introduce a helper function index in order to access your 2D quantity as, say,

接下来,您可以使用向量的成员运算符[](或者如果要进行绑定检查,则使用成员函数)来访问线性存储器。您可能希望在区间[0,N0]和[0,N1)中使用两个索引n0和n1,但内存是线性的并且需要单个索引。因此,您可以引入辅助函数索引以访问您的2D数量,例如,

my_memory[index(n0, n1)] = T(42);

To imagine how this could work consider a 3-by-2 matrix. In the given linear memory block you could arrange the elements like this:

想象一下这是如何工作的,考虑一个3乘2的矩阵。在给定的线性内存块中,您可以像这样排列元素:

         0           1           2           3           4           5
index(0, 0) index(0, 1) index(1, 0) index(1, 1) index(2, 0) index(2, 1)

In which case you would write

在这种情况下你会写

int index(int n0, int n1) {
  return n0 * N1 + n1;// (note that `n0` is multiplied by `N1`).
}

In general for d dimensions you would have (pseudo code)

通常对于d维度你会有(伪代码)

int index(int(&n)[d]) {
  return n[0] * (N[1]*N[2]*...*N[d-1])
    + n[1] * (N[2]*N[3]*...*N[d-1])
    + ...
    + n[d-2] * (N[d-1])
    + n[d-1] * (1);
}

where the expressions in brackets are also called pitches.

括号中的表达式也称为音高。

If you put all that logic in a class, is becomes very simple to use. Here is an example for inspiration (online demo with N = 4):

如果将所有逻辑放在一个类中,则变得非常简单易用。以下是灵感的示例(N = 4的在线演示):

#include <cassert>

#include <iostream>
#include <vector>

template<class T>
class Quantity2d {
 private:
  std::size_t Ns_[2];
  std::vector<T> data_;
 public:
  Quantity2d(int N0, int N1)
  : Ns_{std::size_t(N0), std::size_t(N1)}
  , data_()
  {
    assert(N0 > 0);
    assert(N1 > 0);
    data_.resize(size(), T{});
  }

  constexpr size_t size() const { return Ns_[0] * Ns_[1]; }

  constexpr int N0() const { return int(Ns_[0]); }
  constexpr int N1() const { return int(Ns_[1]); }

  constexpr size_t pitch0() const { return Ns_[1]; }
  constexpr size_t pitch1() const { return std::size_t(1); }

  constexpr size_t ind(int n0, int n1) const {
    assert(n0 >= 0 && n0 < N0());
    assert(n1 >= 0 && n1 < N1());
    return std::size_t(n0) * pitch0() + std::size_t(n1) * pitch1();
  }

  T& operator()(int n1, int n2) {
    return data_[ind(n1, n2)];
  }

  constexpr const T& operator()(int n1, int n2) const {
    return data_[ind(n1, n2)];
  }
};

template<class T>
std::ostream& operator<<(std::ostream& os, const Quantity2d<T>& q) {
  int N0 = q.N0();
  int N1 = q.N1();
  for(int i=0; i<N0; ++i) {
    for(int j=0; j<N1; ++j) {
      os << i << "\t" << j << "\t" << q(i, j) << "\n";
    }
  }
  return os;
}

int main() {
  int N = 0;
  std::cout << "please enter size per dimension "
    << "(WARNING: matrix will be printed on screen): "
    << std::flush;
  std::cin >> N;

  if(N >= 1) {
    std::cout << "I understood. So let's do " << N << "x" << N << std::endl;
  }
  else {
    std::cerr << "You failed. Next time try with N >= 1." << std::endl;
    return 1;
  }

  Quantity2d<double> matrix(N, N);

  for(int i=0; i<matrix.N0(); ++i) {
    for(int j=0; j<matrix.N1(); ++j) {
      matrix(i, j) = double(i) * double(j);
    }
  }

  std::cout << matrix << std::flush;

  return 0;
}

#4


0  

It is possible to create a two dimensional array without using vectors like below. This will work for all the types.

可以在不使用如下矢量的情况下创建二维阵列。这适用于所有类型。

template <typename T> 
T **Alloc2D( int nRows, int nCols)
{
      T **array2D;    
      array2D = new T*[nRows];
      for( int i = 0 ; i < nRows ; i++ )
          array2D[i] = new T [nCols];

      return array2D;
}

template <typename T>
void Free2D(T** dArray)
{
      delete [] *dArray;
      delete [] dArray;
}

But, the problem is memory management as it is a raw approach.

但是,问题在于内存管理,因为它是一种原始方法。

Instead, we can use vectors which is manageable like

相反,我们可以使用可管理的向量

typedef vector<vector<int>> ARRAY2D;

#5


-1  

It is possible:

有可能的:

int **marray = new int[n][n];

#1


2  

Do it with a vector, like this:

用矢量做,像这样:

int n;
cin >> n;
auto matrix = std::vector<std::vector<int>>(n, std::vector<int>(n));

https://wandbox.org/permlink/zsOiUTvCbxAGmK6d


There is also a std::valarray template which is similar functionality as std::vector, but has interesting extra functionality, which can be useful in case of matrix.

https://wandbox.org/permlink/9Vq141QpEWcWoUxM

#2


1  

To create a multidimensional array, you would have to write this:

要创建多维数组,您必须编写以下内容:

int n;
cin >> n;
int **array = new int*[n];
for (int i = 0; i < n; i++) {
    array[i] = new int[n];
}

And don't forget to delete it:

别忘了删除它:

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

But current c++ best practice is to never allocate or deallocate memory in application code, meaning you should use a std::vector or some other container class.

但是当前的c ++最佳实践是永远不要在应用程序代码中分配或释放内存,这意味着你应该使用std :: vector或其他一些容器类。

#3


1  

This answer differs in two points from most of the other answers:

这个答案与其他大多数答案的不同点有两点:

  • no raw pointer or memory allocation
  • 没有原始指针或内存分配

  • use a single contiguous (linear) block of memory
  • 使用单个连续(线性)内存块

A common approach is using a single linear block of memory and storing the elements row after row or column after column (Row- or column-major order). Let us generalize a bit and say you want a 2D quantity of type T with the extents N0 and N1. Then you can obtain the required memory by

一种常见的方法是使用单个线性内存块并在列之后的行或列之后逐行存储元素(行或列主要顺序)。让我们概括一下,并说你想要一个带有范围N0和N1的类型T的2D数量。然后你可以通过获得所需的内存

std::vector<T> my_memory(N0*N1, T{});

Using a vector instead of a raw pointer has several advantages. For example, you can not forget to free the memory because the deconstructor cares about that automatically (RAII idiom). Another advantage is that the constructor called above fills the vector with copies of default-constructed T (instead of leaving the memory uninitialized).

使用向量而不是原始指针有几个优点。例如,你不能忘记释放内存,因为解构器会自动关注它(RAII惯用法)。另一个优点是上面调用的构造函数使用默认构造的T的副本填充向量(而不是使内存保持未初始化)。

Next, you can access the linear memory by using vector's member operator[] (or the member function at if you want bound checks). You probably want to use two indices n0 and n1 in the intervals [0, N0) and [0, N1), but the memory is linear and requires a single index. Hence you can introduce a helper function index in order to access your 2D quantity as, say,

接下来,您可以使用向量的成员运算符[](或者如果要进行绑定检查,则使用成员函数)来访问线性存储器。您可能希望在区间[0,N0]和[0,N1)中使用两个索引n0和n1,但内存是线性的并且需要单个索引。因此,您可以引入辅助函数索引以访问您的2D数量,例如,

my_memory[index(n0, n1)] = T(42);

To imagine how this could work consider a 3-by-2 matrix. In the given linear memory block you could arrange the elements like this:

想象一下这是如何工作的,考虑一个3乘2的矩阵。在给定的线性内存块中,您可以像这样排列元素:

         0           1           2           3           4           5
index(0, 0) index(0, 1) index(1, 0) index(1, 1) index(2, 0) index(2, 1)

In which case you would write

在这种情况下你会写

int index(int n0, int n1) {
  return n0 * N1 + n1;// (note that `n0` is multiplied by `N1`).
}

In general for d dimensions you would have (pseudo code)

通常对于d维度你会有(伪代码)

int index(int(&n)[d]) {
  return n[0] * (N[1]*N[2]*...*N[d-1])
    + n[1] * (N[2]*N[3]*...*N[d-1])
    + ...
    + n[d-2] * (N[d-1])
    + n[d-1] * (1);
}

where the expressions in brackets are also called pitches.

括号中的表达式也称为音高。

If you put all that logic in a class, is becomes very simple to use. Here is an example for inspiration (online demo with N = 4):

如果将所有逻辑放在一个类中,则变得非常简单易用。以下是灵感的示例(N = 4的在线演示):

#include <cassert>

#include <iostream>
#include <vector>

template<class T>
class Quantity2d {
 private:
  std::size_t Ns_[2];
  std::vector<T> data_;
 public:
  Quantity2d(int N0, int N1)
  : Ns_{std::size_t(N0), std::size_t(N1)}
  , data_()
  {
    assert(N0 > 0);
    assert(N1 > 0);
    data_.resize(size(), T{});
  }

  constexpr size_t size() const { return Ns_[0] * Ns_[1]; }

  constexpr int N0() const { return int(Ns_[0]); }
  constexpr int N1() const { return int(Ns_[1]); }

  constexpr size_t pitch0() const { return Ns_[1]; }
  constexpr size_t pitch1() const { return std::size_t(1); }

  constexpr size_t ind(int n0, int n1) const {
    assert(n0 >= 0 && n0 < N0());
    assert(n1 >= 0 && n1 < N1());
    return std::size_t(n0) * pitch0() + std::size_t(n1) * pitch1();
  }

  T& operator()(int n1, int n2) {
    return data_[ind(n1, n2)];
  }

  constexpr const T& operator()(int n1, int n2) const {
    return data_[ind(n1, n2)];
  }
};

template<class T>
std::ostream& operator<<(std::ostream& os, const Quantity2d<T>& q) {
  int N0 = q.N0();
  int N1 = q.N1();
  for(int i=0; i<N0; ++i) {
    for(int j=0; j<N1; ++j) {
      os << i << "\t" << j << "\t" << q(i, j) << "\n";
    }
  }
  return os;
}

int main() {
  int N = 0;
  std::cout << "please enter size per dimension "
    << "(WARNING: matrix will be printed on screen): "
    << std::flush;
  std::cin >> N;

  if(N >= 1) {
    std::cout << "I understood. So let's do " << N << "x" << N << std::endl;
  }
  else {
    std::cerr << "You failed. Next time try with N >= 1." << std::endl;
    return 1;
  }

  Quantity2d<double> matrix(N, N);

  for(int i=0; i<matrix.N0(); ++i) {
    for(int j=0; j<matrix.N1(); ++j) {
      matrix(i, j) = double(i) * double(j);
    }
  }

  std::cout << matrix << std::flush;

  return 0;
}

#4


0  

It is possible to create a two dimensional array without using vectors like below. This will work for all the types.

可以在不使用如下矢量的情况下创建二维阵列。这适用于所有类型。

template <typename T> 
T **Alloc2D( int nRows, int nCols)
{
      T **array2D;    
      array2D = new T*[nRows];
      for( int i = 0 ; i < nRows ; i++ )
          array2D[i] = new T [nCols];

      return array2D;
}

template <typename T>
void Free2D(T** dArray)
{
      delete [] *dArray;
      delete [] dArray;
}

But, the problem is memory management as it is a raw approach.

但是,问题在于内存管理,因为它是一种原始方法。

Instead, we can use vectors which is manageable like

相反,我们可以使用可管理的向量

typedef vector<vector<int>> ARRAY2D;

#5


-1  

It is possible:

有可能的:

int **marray = new int[n][n];