4

I'm a high school student learning programming and I have a problem that I can't figure out how to solve.

I have an integer "x", and I want a matrix "mat" to have the size of "x":

int mat[x][x];

But that works only in main() where I've read x;

For example if x == 5, the equivalent would be

int mat[5][5];

#include <iostream>
using namespace std;

int x;

int mat[x][x];

void f(int mat2[x][x])
{

}

int main()
{
    cin >> x;
    int m[x][x];
    f(m);
}

I've wrote this short program to show where it works and it doesn't work.

error: array bound is not an integer constant before ']' token

I've the error at the global declaration, at the declaration in function void f. It only compiles without errors in main();

What can I do to create a matrix with the size of x outside of the main function?

AndyG
  • 39,700
  • 8
  • 109
  • 143
Christian C
  • 369
  • 3
  • 10
  • You cannot do that, use a `std::vector>` and `resize()` instead. – πάντα ῥεῖ Mar 06 '17 at 13:55
  • Typically you do not want global variables as they make the code harder to reason. – NathanOliver Mar 06 '17 at 13:55
  • 2
    `cin >> x; int m[x][x];` only works because of compiler extensions - it is **not** standard C++. In addition, you would need to [read a good book on C++](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). Programming by guessing is not the way to learn. – Algirdas Preidžius Mar 06 '17 at 13:55
  • Size of array must be a `const` which means you can't do what you intended. To allocate size dynamically at run time, use int pointer. If you want the size to grow and shirnk, use vector. – user3437460 Mar 06 '17 at 14:00
  • 5
    OP is clearly a newcomer to C++, but their question is pretty good, contains a [mcve], gives the specific error... +1 – YSC Mar 06 '17 at 14:04
  • 2
    @YSC But, lacks research. Which is why I downvoted. – Algirdas Preidžius Mar 06 '17 at 14:05
  • 1
    @Algirdas Preidžius Trust me, I did research, and all the answers said why the error shows, nobody said that you can't do that, and nobody asked if or how you can do that. – Christian C Mar 06 '17 at 14:17
  • 1
    @CristiCristi _"Trust me, I did research ..."_ It's obvious you didn't. – πάντα ῥεῖ Mar 06 '17 at 14:21
  • C99 support variable-length arrays, btw... – moooeeeep Mar 06 '17 at 14:22
  • @CristiCristi I, simply, don't believe that _all_ answers were like that. This topic (code execution flow) should be covered at the beginning of any, decent, C++ book, at the very least. – Algirdas Preidžius Mar 06 '17 at 14:22
  • @moooeeeep Since C99 is C standard, and this question is tagged with C++, I fail to see how that would apply. – Algirdas Preidžius Mar 06 '17 at 14:24
  • 1
    @AlgirdasPreidžius To introduce a keyword that might help the OP researching the feature he is looking for: http://stackoverflow.com/q/1887097/1025391 – moooeeeep Mar 06 '17 at 14:28
  • When you want to create an array `x` must be known at compile time. That's not the case. Try with `std::vector>` – Jepessen Mar 07 '17 at 07:57

5 Answers5

3

Variable length arrays aren't spported in standard c++. Besides you don't want the global definition.

What you can use portably in that case is std::vector:

void f(std::vector<std::vector<int>>& mat)
{

}

int main()
{
    cin >> x;
    std::vector<std::vector<int>> m(x,std::vector<int>(x));
    f(m);
}

If you pass that vector around to functions or being allocated within functions, the size information will be kept at any time.

What can I do to create a matrix with the size of x outside of the main function?

Something like this:

std::vector<std::vector<int>> foo() {
    cin >> x;
    std::vector<std::vector<int>> m(x,std::vector<int>(x));
    return m;
}

int main()
{
    std::vector<std::vector<int>> mat = foo();
}
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
1

Handling of multi-dimension arrays in C++ is not easy. The best way to go is often to map a multi-dimensionnal indexing with a linear memory chunk.

For instance, for a 2 by 2 matrix, one can create an array of 2*2=4 elements and map it this way:

+-----------+-----------+-----------+-----------+
| map[0][0] | map[0][1] | map[1][0] | map[1][1] |
+-----------+-----------+-----------+-----------+

This seems overly complicated at first glance, but it simplifies greatly the memory allocation.

For an arbitrary sized matrix of width by height, map[i][j] is at index i*height + j. This can be translated in C++, encapsulated in a template class Matrix:

#include <array>
template <typename T, size_t WIDTH, size_t HEIGHT>
class Matrix {
    std::array<T, WIDTH*HEIGHT> data;

public:    
    T& operator()(size_t i, size_t j) {
        return data[i*HEIGHT + j];
    }
    const T& operator()(size_t i, size_t j) const {
        return data[i*HEIGHT + j];
    }
};

This has the disadvantage that the Matrix' dimensions must be known at compile time (and can be mitigated, see note (ii) at end of answer). But it makes its use so easy:

void fill(Matrix<int, 2, 2>& m) {
    m(0,0) = 0;
    m(0,1) = 1;
    m(1,0) = 2;
    m(1,1) = 3;
}

int main() {
    Matrix<int, 2, 2> m;
    fill(m);
    std::cout << m(1,0) << "\n";
}

Note (i): Elements are indexed by (line, column) rather than [line][column] because we can't create an operator[] accepting multiple values.

Live on coliru

Note (ii): This basic idea can be enriched (demo) to handle resizable matrixes, with use of a std::vector instead of std::array and a proxy to std::vector::resize().

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
YSC
  • 38,212
  • 9
  • 96
  • 149
0

Variable-length array is supported by some compiler as an extension. The manual of the compiler provides more information.Gnu VLR

The storage duration of a variable-length array(if supported) generally can't be static, which is why you get the error message (global variables have static storage duration).

Unrelated: The major array bound of the parameter mat2 isn't necessary, i.e. void f(int mat2[x][x]) is equivalent to void f(int mat2[][x]).

felix
  • 2,213
  • 7
  • 16
0

C++ has no provision for dynamic 2D matrix but provides all you need to create complex classes. A (static) 2D array is a contiguously allocated array of height arrays of width elements. Just mimic that and:

  • allocate a linear array of width * height
  • provide an operator[](int) that returns a pointer to the first element of ith row
  • do necessary housekeeping in destructor and in a copy (and move if C++11 or above) constructor.

Example of code:

template <typename T>
class Matrix {
    T *data;
    int width;
    int height;

public:
    // direct ctor
    Matrix(int h, int w): width(w), height(h) {
        data = new T[w * h];
    }

    //copy ctor
    Matrix(const Matrix& src): width(src.width), height(src.height) {
        data = new T[width * height];   // allocate and copy data array
        for (int i=0; i<width * height; i++) data[i] = src.data[i];
    }

    // move ctor
    Matrix(Matrix&& src): width(src.width), height(src.height) {
        data = src.data;  // steal original array in a move
        src.data = NULL;  // ensure no deletion will occur at src destruction
    }

    ~Matrix() {
        delete data;
        data = NULL;
    }

    // explicitely delete assignement operators
    Matrix& operator = (const Matrix&) = delete;
    Matrix& operator = (Matrix&&) = delete;

    T* operator[](int i) {
        //optionaly test 0 <= i < width
        return &data[i * width];
    }
};

int main()
{
    int w;
    std::cin >> x;
    Matrix<int> m(x, x);
    // you can then use m[i][j] as you would for a static 2D array
    ...
}

This class does not support any resizing by design. If you need that, you really should use a vector<vector<T> >. The downside is that it has no default ctor either, because the dimension must be given at definition time (even if we could easily imagine a 2 phases initialization...).

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
-1

You can dynamic allocate memory to use, in the c/c++, it does not support dynamic size of static memory allocation, so, you just modify your code like this.

int x;
cin >>x;
int** mat = new int[x][x];
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
xiangjian Wu
  • 116
  • 1
  • 1
  • 8
  • Why using `new` here? C++ provides any kind of containers and smart pointers to avoid that, since it's very error prone to use. Besides that your proposal won't work properly. – πάντα ῥεῖ Mar 06 '17 at 14:18
  • The container is easy to use. but, I think some one can operate the memory, it is good for to develop others, like big project. I just post example code.. – xiangjian Wu Mar 06 '17 at 14:26