1

I'm trying to learn c++, I started working with Two Dimensional Arrays. I decided to begin with simple - fill and print functions. I have done it before with a one-dimensional array, but I have a little problem with it now. I can see "|35|error: cannot convert 'int (*)[10]' to 'int**'|" error Thats my code

#include <iostream>
#include <cmath>
#include <time.h>
#include <cstdlib>

using namespace std;

void Fill(int ** T, int x, int y){
srand(time(NULL));

    for(int i = 0; i<y; i++){
        for(int j = 0; j<x; j++){
            T[i][j] = rand()%100;
        }
    }
}

void Print(int ** T, int x, int y){
    for(int j = 0; j<y; j++){
        for(int i = 0; i<x; i++){
            cout<<T[i][j]<<" ";
        }
        cout << endl;
    }
}



int main()
{

int T[10][10];
Fill(T, 10, 10);
Print(T, 10, 10);


}

What did i wrong ? Did I give arguments correctly ?

KermitHQ
  • 33
  • 5
  • You should start with [`std::array`](https://en.cppreference.com/w/cpp/container/array) instead of C style arrays. Your code looks like legacy code. That's not how you should start learning C++. C++ arrays solve your problem. – Thomas Sablik May 21 '21 at 19:37
  • A 2D array does not translate to a pointer to a pointer as you have no doubt noticed. `int T[10][10]` converts to `int (*)[10]`. You need to provide all but the first dimension of the array so that the compiler can generate the correct indexing math for you, making it extremely hard to pass a 2D array around unless you know ahead of time what those fixed dimensions are. My usual work around is to use 1D arrays and perform all of the indexing math myself. I make this easier with a wrapper class that contains the array and provides methods to do the correct indexing. – user4581301 May 21 '21 at 19:47
  • [Here is a simple example based around a `std::vector`](https://stackoverflow.com/a/2076668/4581301) – user4581301 May 21 '21 at 19:47
  • 1
    @user4581301: Interestingly your observation "it is extremely hard to pass a 2D array around unless you know ahead of time what those fixed dimensions are" applies equally to the recommendation others are making of `std::array`. For plain old legacy arrays, non-type template parameters can save you from knowing the fixed dimensions (as long as they are fixed at compile-time the compiler will automatically infer template arguments) – Ben Voigt May 21 '21 at 19:55

2 Answers2

0

You should start with std::array instead of C style arrays. Your code looks like legacy code. That's not how you should start learning C++. C++ arrays solve your problem.

#include <array>
#include <iostream>
#include <cmath>
#include <ctime>
#include <cstdlib>

using namespace std;

using MyArray = std::array<std::array<int, 10>, 10>;

void Fill(MyArray &T){
    srand(time(NULL));

    for(auto &row : T){
        for(auto &el : row){
            el = rand()%100;
        }
    }
}

void Print(const MyArray &T){
    for(auto &row : T){
        for(auto &el : row){
            cout<<el<<" ";
        }
        cout << endl;
    }
}

int main()
{
    MyArray T;
    Fill(T);
    Print(T);
}
Thomas Sablik
  • 16,127
  • 7
  • 34
  • 62
  • 1
    @ChandraPrakashDixit Yes, for `time`. – Thomas Sablik May 21 '21 at 19:49
  • Note that `using MyArray = int[10][10];` would have made OP's legacy array code look just as nice -- there's not actually any advantage to `std::array` here, the type alias is doing all the heavy lifting. – Ben Voigt May 21 '21 at 19:59
  • Also, `` only works here because of the (ill-advised) `using namespace std;` In general `#include ` will give you a global function `time()` and `#include ` will give you `std::time()`. They aren't guaranteed to give the other name as well, although they can; assuming that they do leads to non-portable code. – Ben Voigt May 21 '21 at 20:01
  • @ThomasSablik actually using `std::random_device` and alike instead of `rand` might be better (more C++, less C) but I might be being picky here. – alagner May 21 '21 at 20:01
0

To complete the answer:

int T[10][10];

is a group of contiguous ints with no pointers involved, whereas

int **

should point on an int *. That's the reason why you cannot convert T to an int **

When you write T[i][j] you are doing pointer arithmetic using a pointer of type int (*p)[10] then a pointer of type int *p. Again no pointer is stored into T. Here is a concrete example:

#include <iostream>

template <size_t COLUMN_SIZE>
int
get_Tij(int T[][COLUMN_SIZE], int i, int j)
{
  // A pointer on an array of COLUMN_SIZE ints
  int(*p)[COLUMN_SIZE] = T;

  // Select row i, the stride is COLUMN_SIZE*sizeof(int)
  int* p_i = p[i];

  // Select column j, the stride is sizeof(int)
  int p_ij = p_i[j];

  return p_ij;
}

int
main()
{
  int T[2][3] = {{0, 1, 2}, {3, 4, 5}};

  std::cout << "\n" << get_Tij(T, 0, 0);
  std::cout << "\n" << get_Tij(T, 0, 1);
  std::cout << "\n" << get_Tij(T, 1, 0);

  std::cout << "\n" << T[0][0];
  std::cout << "\n" << T[0][1];
  std::cout << "\n" << T[1][0];
}

which prints

0
1
3
0
1
3

If you want to learn C++, as already said in comment/other answers, you should use std::array (for static size vectors) or std::vector (for dynamic size vectors)

Picaud Vincent
  • 10,518
  • 5
  • 31
  • 70