2

I am a Fortran user and do not know C++ well enough. I need to make some additions into an existing C++ code. I need to create a 2d matrix (say A) of type double whose size (say m x n) is known only during the run. With Fortran this can be done as follows

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

How do I create a matrix A(m,n), in C++, when m and n are not known at the time of compilation? I believe the operator new in C++ can be useful but not not sure how to implement it with doubles. Also, when I use following in C++

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

and check the size of x using sizeof(x)/sizeof(x[0]), I do not have 10, any comments why?

10
  • 1
    x is a pointer, not an array.
    – David G
    Commented Jul 22, 2014 at 17:10
  • 1
    Use a 2D matrix class.
    – chris
    Commented Jul 22, 2014 at 17:10
  • 1
    Generally you should flatten out your data into one single, dynamic array and access it in strides.
    – Kerrek SB
    Commented Jul 22, 2014 at 17:11
  • 2
    boost::multi_array Commented Jul 22, 2014 at 17:15
  • 1
    Whatever method you decide to use, if you are moving from fortran and especially if you are translating from fortran to C++, remember the zero-based indexing in C++ (index goes from 0 to n-1 instead of from 1 to n). Also, in fortran multidimensional arrays are column-ordered (stored in memory, the first index changes the fastest) but in C++ they are row-ordered (stored in the memory, the last index changes the fastest).
    – triple_r
    Commented Jul 22, 2014 at 18:29

5 Answers 5

2

To allocate dynamically a construction similar to 2D array use the following template.

#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;
}

Also you can use class std::vector instead of the manually allocated pointers.

#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 ) );

   //...

}

As for this code snippet

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

then x has type int * and x[0] has type int. So if the size of the pointer is equal to 4 and the size of an object of type int is equal also to 4 then sizeof( x ) / sizeof( x[0] ) will yields 1. Pointers do not keep the information whether they point to only a single object or the first object pf some sequence of objects.

1

I would recommend using std::vector and avoid all the headache of manually allocating and deallocating memory.

Here's an example program:

#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);
}
0

The formal C++ way of doing it would be this:

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

This creates container which contains a zero size set of sub-containers. C++11/C++13 provide std::array for fixed-sized containers, but you specified runtime sizing.

We now have to impart our dimensions on this and, unfortunately. Lets assign the top-level:

a.resize(10);

(you can also push or insert elements)

What we now have is a vector of 10 vectors. Unfortunately, they are all independent, so you would need to:

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

We now have a 10x10. We can also use vectors constructor:

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

Note that vectors are fully dynamic, so we can resize elements as we need:

 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

To get the size of a particular slot:

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

Unfortunately C++ doesn't provide a strong, first-class way to allocate an array that retains size information. But you can always create a simple C-style array on the stack:

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

But using an allocator, that is placing the data onto the heap, requires /you/ to track size.

int* pointer = new int[10];

At this point, "pointer" is a numeric value, zero to indicate not enough memory was available or the location in memory where the first of your 10 consecutive integer storage spaces are located.

The use of the pointer decorator syntax tells the compiler that this integer value will be used as a pointer to store addresses and so allow pointer operations via the variable.

The important thing here is that all we have is an address, and the original C standard didn't specify how the memory allocator would track size information, and so there is no way to retrieve the size information. (OK, technically there is, but it requires using compiler/os/implementation specific information that is subject to frequent change)

These integers must be treated as a single object when interfacing with the memory allocation system -- you can't, for example:

delete pointer + 5;

to delete the 5th integer. They are a single allocation unit; this notion allows the system to track blocks rather than individual elements.

To delete an array, the C++ syntax is

delete[] pointer;

To allocate a 2-dimensional array, you will need to either:

Flatten the array and handle sizing/offsets yourself:

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]

or you could use

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];
}

That's kind of a pain, so you would probably be steered towards encapsulation:

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);

Or,

For each Nth dimension (N < dimensions) allocate an array of pointers-to-pointers, only allocating actual ints for the final dimension.

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;

This last is more-or-less doing the same work, it just creates more memory fragmentation than the former.

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

To answer the question "why do I not have 10" you're probably compiling in 64-bit mode, which means that "x" is an array of 10 pointers-to-int, and because you're in 64-bit mode, pointers are 64-bits long, while ints are 32 bits.

2
  • This post started off well but then degenerated into new. There is no reason whatsoever to use new for this task . Your Array2D should use vector to manage its memory.
    – M.M
    Commented Jul 22, 2014 at 21:21
  • "Unfortunately C++ doesn't provide a strong, first-class way to allocate an array that retains size information. " - yes it does, std::array< std::array<int, 10>, 10 >
    – M.M
    Commented Jul 22, 2014 at 21:25
0

The C++ equivalent of your Fortran code is:

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

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

To access an element of this array you would need to write A[r * rows + c] (or you could do it in a column-major fashion, that's up to you).

The element access is a bit clunky, so you could write a class that wraps up holding this vector and provides a 2-D accessor method.

In fact your best bet is to find a free library that already does this, instead of reinventing the wheel. There isn't a standard Matrix class in C++, because somebody would always want a different option (e.g. some would want row-major storage, some column-major, particular operations provided, etc. etc.)

Someone suggested boost::multi_array; that stores all its data contiguously in row-major order and is probably suitable. If you want standard matrix operations consider something like Eigen, again there are a lot of alternatives out there.

If you want to roll your own then it could look like:

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;
};

Note in particular that by avoiding new you avoid the thousand and one headaches that come with manual memory management. Your class is copyable and movable by default. You could add further methods to replicate any functionality that the Fortran array has which you need.

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

Unfortunately you'll have to store the size of matrix somewhere else. C/C++ won't do it for you. sizeof() works only when compiler knows the size, which is not true in dynamic arrays.

And if you wan to achieve it with something more safe than dynamic arrays:

#include <vector>
// ...

std::vector<std::vector<int>> vect(10, std::vector<int>(5));
vect[3][2] = 1;
1
  • 2
    If you're teaching how to use new, you better well also be teaching delete. Commented Jul 22, 2014 at 18:12

Not the answer you're looking for? Browse other questions tagged or ask your own question.