在C ++中声明和分配2d数组

时间:2014-07-22 17:09:22

标签: c++ arrays dynamic-arrays

我是Fortran用户,并且不太了解C ++。我需要在现有的C ++代码中添加一些内容。我需要创建一个double类型的二维矩阵(比如A),其大小(比如m x n)只在运行期间才知道。使用Fortran,可以按照以下方式完成

real*8, allocatable :: A(:,:)
integer :: m, n    
read(*,*) m
read(*,*) n
allocate(a(m,n))
A(:,:) = 0.0d0

如果在编译时不知道m和n,如何在C ++中创建矩阵A(m,n)?我相信C ++中的运算符new可能很有用但不能确定如何用双精度实现它。另外,当我在C ++中使用以下

int * x;
x = new int [10];

并使用sizeof(x)/sizeof(x[0])检查x的大小,我没有10,任何评论为什么?

5 个答案:

答案 0 :(得分:2)

要动态分配类似于2D数组的构造,请使用以下模板。

#include <iostream>

int main()
{
   int m, n;

   std::cout << "Enter the number of rows: ";
   std::cin >> m;

   std::cout << "Enter the number of columns: ";
   std::cin >> n;

   double **a = new double * [m];

   for ( int i = 0; i < m; i++ ) a[i] = new double[n]();

   //...

   for ( int i = 0; i < m; i++ ) delete []a[i];
   delete []a;
}

此外,您可以使用类std::vector而不是手动分配的指针。

#include <iostream>
#include <vector>

int main()
{
   int m, n;

   std::cout << "Enter the number of rows: ";
   std::cin >> m;

   std::cout << "Enter the number of columns: ";
   std::cin >> n;

   std::vector<std::vector<double>> v( m, std::vector<double>( n ) );

   //...

}

至于此代码段

int * x;
x = new int [10];

然后x的类型为int *x[0]的类型为int。因此,如果指针的大小等于4并且int类型的对象的大小也等于4,则sizeof( x ) / sizeof( x[0] )将产生1.指针不保留信息,无论它们是指向单个对象还是某些对象序列的第一个对象。

答案 1 :(得分:1)

我建议使用std::vector并避免手动分配和释放内存的所有麻烦。

这是一个示例程序:

#include <iostream>
#include <vector>

typedef std::vector<double> Row;
typedef std::vector<Row> Matrix;

void testMatrix(int M, int N)
{
   // Create a row with all elements set to 0.0
   Row row(N, 0.0);

   // Create a matrix with all elements set to 0.0
   Matrix matrix(M, row);

   // Test accessing the matrix.
   for ( int i = 0; i < M; ++i )
   {
      for ( int j = 0; j < N; ++j )
      {
         matrix[i][j] = i+j;
         std::cout << matrix[i][j] << " ";
      }
      std::cout << std::endl;
   }
}

int main()
{
   testMatrix(10, 20);
}

答案 2 :(得分:0)

正式的C ++方式是这样的:

std::vector<std::vector<int>> a;

这将创建包含零容量子容器集的容器。 C ++ 11 / C ++ 13为固定大小的容器提供std::array,但是您指定了运行时大小调整。

我们现在不得不在此基础上传授我们的维度。让我们分配顶级:

a.resize(10);

(您还可以pushinsert元素)

我们现在拥有的是10个向量的vector。不幸的是,它们都是独立的,所以你需要:

for (size_t i = 0; i < a.size(); ++i) {
    a[i].resize(10);
}

我们现在有10x10。我们也可以使用vector的构造函数:

 std::vector<std::vector<int>> a(xSize, std::vector<int>(ySize)); // assuming you want a[x][y]

请注意,向量是完全动态的,因此我们可以根据需要调整元素大小:

 a[1].push_back(10); // push value '10' onto a[1], creating an 11th element in a[1]
 a[2].erase(2); // remove element 2 from a[2], reducing a[2]s size to 9

获取特定广告位的尺寸:

 a.size(); // returns 10
 a[1].size(); // returns 11 after the above
 a[2].size(); // returns 9 after teh above.

不幸的是,C ++并没有为分配保留大小信息的数组提供强大的一流方法。但是你总是可以在堆栈上创建一个简单的C风格数组:

int a[10][10];
std::cout << "sizeof a is " << sizeof(a) <<'\n';

但是使用分配器,即将数据放到堆上,需要/你/跟踪大小。

int* pointer = new int[10];

此时,&#34;指针&#34;是一个数值,零表示没有足够的可用内存,或者是内存中10个连续整数存储空间中第一个所在的位置。

使用指针装饰器语法告诉编译器这个整数值将被用作指向存储地址的指针,因此允许通过变量进行指针操作。

重要的是,我们拥有的只是一个地址,原始的C标准没有规定内存分配器如何跟踪大小信息,因此无法检索大小信息。 (好的,技术上有,但它需要使用经常更改的编译器/操作系统/实现特定信息)

在与内存分配系统连接时,必须将这些整数视为单个对象 - 例如:

delete pointer + 5;

删除第5个整数。他们是一个allocation unit;这个概念允许系统跟踪块而不是单个元素。

要删除数组,C ++语法为

delete[] pointer;

要分配二维数组,您需要:

展平阵列并自行处理尺寸调整/偏移:

static const size_t x = 10, y = 10;
int* pointer = new int[x * y];
pointer[0] = 0; // position 0, the 1st element.
pointer[x * 1] = 0; // pointer[1][0]

或者您可以使用

int access_2d_array_element(int* pointer, const size_t xSize, const size_t ySize, size_t x, size_t y)
{
    assert(x < xSize && y < ySize);
    return pointer[y * xSize + x];
}

那种痛苦,所以你可能会转向封装:

class Array2D
{
    int*         m_pointer;
    const size_t m_xSize, m_ySize;
public:
    Array2D(size_t xSize, size_t ySize)
        : m_pointer(new int[xSize * ySize])
        , m_xSize(xSize)
        , m_ySize(ySize)
    {}

    int& at(size_t x, size_t y)
    {
        assert(x < m_xSize && y < m_ySize);
        return m_pointer[y * m_xSize + x];
    }

    // total number of elements.
    size_t arrsizeof() const
    {
        return m_xSize * m_ySize;
    }

    // total size of all data elements.
    size_t sizeof() const
    {
        // this sizeof syntax makes the code more generic.
        return arrsizeof() * sizeof(*m_pointer);
    }

    ~Array2D()
    {
        delete[] m_pointer;
    }
};

Array2D a(10, 10);
a.at(1, 3) = 13;
int x = a.at(1, 3);

或者,

对于每个第N个维度(N&lt;维度),分配一个指针到指针的数组,仅为最终维度分配实际的内容。

const size_t xSize = 10, ySize = 10;
int* pointer = new int*(x); // the first level of indirection.
for (size_t i = 0; i < x; ++i) {
    pointer[i] = new int(y);
}
pointer[0][0] = 0;
for (size_t i = 0; i < x; ++i) {
    delete[] pointer[i];
}
delete[] pointer;

最后这个或多或少做同样的工作,它只是创造了比前者更多的内存碎片。

----------- ----------- EDIT

回答问题&#34;为什么我没有10&#34;您可能正在以64位模式进行编译,这意味着&#34; x&#34;是一个10指针到int的数组,因为你处于64位模式,指针是64位长,而整数是32位。

答案 3 :(得分:0)

您的Fortran代码的C ++等价物是:

int cols, rows;
if ( !(std::cin >> cols >> rows) )
     // error handling...

std::vector<double> A(cols * rows);

要访问此数组的元素,您需要编写A[r * rows + c](或者您可以按照专栏方式执行此操作,这取决于您)。

元素访问有点笨重,所以你可以编写一个包含这个vector的类,并提供一个2-D访问器方法。

事实上,你最好的办法是找到一个已经做到这一点的免费图书馆,而不是重新发明轮子。在C ++中没有标准的Matrix类,因为有人总是想要一个不同的选项(例如,有些人想要行主要存储,一些列主要,提供特定操作等等)。

有人建议boost::multi_array;以行主顺序连续存储其所有数据并且可能是合适的。如果你想要标准矩阵运算考虑类似Eigen之类的东西,那么还有很多替代方案。

如果你想自己滚动,那么它可能看起来像:

struct FortranArray2D   // actually easily extensible to any number of dimensions
{
    FortranArray2D(size_t n_cols, size_t n_rows)
        : n_cols(n_cols), n_rows(n_rows), content(n_cols * n_rows) { }

    double &operator()(size_t col, size_t row) 
        { return content.at(row * n_rows + col); }

    void resize(size_t new_cols, size_t new_rows)
    { 
         FortranArray2D temp(new_cols, new_rows);
         // insert some logic to move values from old to new...
         *this = std::move(temp);
    }

private:
    size_t n_rows, n_cols;
    std::vector<double> content;
};

请特别注意,通过避免new,您可以避免手动内存管理带来的一千零一个麻烦。默认情况下,您的课程是可复制和可移动的。您可以添加更多方法来复制Fortran阵列所需的任何功能。

答案 4 :(得分:-2)

int ** x;
x = new int* [10];
for(int i = 0; i < 10; i++)
    x[i] = new int[5];

不幸的是,您必须在其他地方存储矩阵的大小。 C / C ++不会为你做这件事。 sizeof()仅在编译器知道大小时才有效,而在动态数组中则不行。

如果你想用比动态数组更安全的东西来实现它:

#include <vector>
// ...

std::vector<std::vector<int>> vect(10, std::vector<int>(5));
vect[3][2] = 1;