Reputation: 257
I am learning C++ with experiencein mostly Python, R and SQL.
The way arrays (and vectors which differes somehow from 1d-arrays? and matrices which are 2d-arrays?) work in C++ seems quite different as I cannot specify the size of dimension of the array with an argument from the function.
A toy-example of my goal is some thing like this:
Have a function my_2d_array which takes two arguments M and N and returns a matrix or 2d-array of dimension (MxN) with elements indicating the position of that element. E.g. calling my_2d_array(4,3) would return:
[[00, 01, 02],
[10, 11, 12],
[20, 21, 22],
[30, 31, 32]]
The main function should execute my_2d_array and be able to potentially perform calculations with the result or modify it.
This is my attempt (with errors):
int my_2d_array(int N, int M) {
int A[N][M];
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i][j] = element;
}
}
return A;
}
void main() {
int N, M;
N = 4;
M = 3;
int A[N][M] = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i][j] << " ";
}
std::cout << "\n";
}
}
One (1) dimensional attempt of @JustLearning's suggestion:
int my_array(int N) {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
int N = 4;
int A[N] = my_array(N);
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << A[i] << " ";
}
}
Upvotes: 2
Views: 1837
Reputation: 13269
Following your comment, I can see why you are confused in your attempts to use a matrix in code.
There are many types of containers in C++. Many of them you can find in the standard library (std::vector
, std::list
, std::set
, ...), others you can create yourself or use other libraries. Plain arrays (like int a[5]
) are a somewhat unique case because they come from C and are part of the language itself.
A plain array lives on the stack (not very important but you might want to read up on stack vs heap allocations), and refers to a contiguous region of memory.
If you declare some array a
like int a[5]
, you get a region of 5 integers one after the other, and you can point to the first one by just writing a
. You can access each of them using a[i]
or, equivalently, *(a+i)
.
If you declare a
like int a[5][3]
, you now get a region of 15 integers, but you can access them slightly differently, like a[i][j]
, which is equivalent to *(a+i*3+j)
.
The important thing to you here is that the sizes (5 and 3) must be compile-time constants, and you cannot change them at runtime.
The same is true for std::array
: you could declare a
like std::array<std::array<int, 3, 5> a
and get a similar region of 15 integers, that you can access the same way, but with some convenience (for example you can return that type, whereas you cannot return a plain array type, only a pointer, losing the size information in the process).
My advice is not to think of these arrays as having dimensionality, but as simple containers that give you some memory to work with however you choose. You can very well declare a
like std::array<int, 15> a
and access elements in a 2D way by indexing like this: a[i*3+j]
. Memory-wise, it's the same.
Now, if you want the ability to set the sizes at runtime, you can use std::vector
in a similar way. Either you declare a
like std::vector<std::vector<int>> a(5, std::vector<int>(3))
and deal with the nested vectors (that initialization creates 5 std::vector<int>
of size 3 each), or you declare a
as a single vector like std::vector<int> a(15)
and index it like a[i*3+j]
. You can even make your own class that wraps a vector and helps with the indexing.
Either way, it's rare in C++ to need a plain array, and you should generally use some kind of container, with std::vector
being a good choice for a lot of things.
Here is an example of how your code would look like using vectors:
#include <vector>
#include <string>
#include <iostream>
std::vector<std::string> my_2d_array(int N, int M) {
std::vector<std::string> A(N*M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A[i*M+j] = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
std::vector<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A[i*M+j] << " ";
}
std::cout << "\n";
}
}
And here is a very crude example of a Matrix class used to wrap the vectors:
#include <vector>
#include <string>
#include <iostream>
template<typename T>
class Matrix {
public:
Matrix(int rowCount, int columnCount) : v(rowCount*columnCount), columnCount(columnCount) {}
T& operator()(int row, int column) {
return v[row*columnCount + column];
}
private:
std::vector<T> v;
int columnCount;
};
Matrix<std::string> my_2d_array(int N, int M) {
Matrix<std::string> A(N, M);
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::string element = std::to_string(i) + std::to_string(j);
A(i, j) = element;
}
}
return A;
}
int main() {
int N, M;
N = 4;
M = 3;
Matrix<std::string> A = my_2d_array(N, M);
// Print the array A
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
std::cout << A(i, j) << " ";
}
std::cout << "\n";
}
}
Upvotes: 1
Reputation: 2302
Welcome to C++! Your function my_2d_array
has a couple of issues:
int
, however you are attempting to return an array of int
s.A
, you must be aware of how it should be passed to a new variable in the main
part of the code. In particular, your code is passing a reference to a temporary variable A
, which is not permitted or safe.In addition, in C++, unless you know what you're doing, main
should always return an int
:
int main() { ... }
What is not clear from your question is whether you are attempting to implement your own "array" class, or simply want to use arrays already established in the standard. For the latter, std::array is a good place to start. The advantage is that you can return std::array
s from functions like you return int
s or double
s.
std::array
s are good if you plan to work with arrays of fixed size, as the size becomes part of the type: std::array<int, 3> my_array;
. Then you can fill it in manually or with member functions of the class (see dox linked above).
If for some reason you prefer to work with arrays of dynamical size (sizes that will change during running your program), std::vector
is the way to go.
Finally, if you are actually learning C++ by attempting to implement a container MyArray
, you should specify that in your question and be a bit more specific in what help you need.
Here's a working example in 1d:
#include <iostream>
#include <array>
template <int N>
std::array<int, N> my_array() {
std::array<int, N> A;
for (int i = 0; i < N; i++) {
A[i] = i;
}
return A;
}
int main() {
const int N = 4;
std::array<int, N> arr = my_array<N>();
// Print the array A
for (int i = 0; i < N; i++) {
std::cout << arr[i] << " ";
}
}
Since the size of a std::array
is included it its type, you need to create a function template, which is basically a function that works for different types. (In C++, std::array<int, 3>
and std::array<int, 4>
are considered different types.)
In order to use this in main
, the index is promoted to a const int
, as plain int
s can vary during run time, and therefore are not suitable for defining types. (In C++ jargon, look up constant expressions).
Finally, note that both the return type and the type of the variable that receives the value returned by the function must be std::array
, not int
as you tried in your 1d code.
Upvotes: 2
Reputation: 235
You can use a 2d vector like this
vector<vector int> A;
It works the same way as a 2d array
Upvotes: 2