My problem:
I have the following piece of code that is a wrapper for 2D square matrices in order to transpose them and print them. I cannot understand why we can write this:
arrayNN(T DATA[N][N]){
n = N;
data = DATA; }
In particular this line of code:data = DATA;.
My thoughts:
As far as i know, in C/C++ you cannot give the values of a matrix to another matrix. For example this piece of code doesn't work, no matter how we write the definition of b:
double array[3][3] = { {11,12,13},{21,22,23},{31,32,33}};
//only one definition
//double **b;
//double *b[3]
double b[3][3];
b = array;
Code: It works.
#include <iostream>
using namespace std;
template <typename T, size_t N>
class arrayNN {
private:
int n;
T (*data)[N]; # a vector of N elements of pointers to datatype T = 2d matrix
public:
arrayNN(): n(N), data(NULL) {};
arrayNN(T DATA[N][N]){
n = N;
data = DATA;
}
void print(ostream &out){
for(int i = 0;i<N;i++){
for(int j=0;j<N; j++){
cout << data[i][j] << '\t';
}
cout << endl;
}
}
void transpose(){
for(int i = 0;i<N;i++){
for(int j=0;j<i; j++){
T temp = data[i][j];
data[i][j] = data[j][i] ;
data[j][i] = temp;
}
}
}
};
int main(){
double array[3][3] = { {11,12,13},{21,22,23},{31,32,33}};
arrayNN<double,3> A(array);
A.print(cout);
A.transpose();
A.print(cout);
return 0;
}
T (*data)[N]; # a vector of N elements of pointers to datatype T = 2d matrix
No, data is not a vector or an array. Instead it is a pointer to an array of size N with elements of type T.
This means that when you wrote data = DATA; you're actually assigning the pointer DATA to the pointer data. Note that the function parameter DATA is a pointer and not an array. You can refer to What is array to pointer decay? for seeing why DATA is a pointer.
Related
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] << " ";
}
}
You can use a 2d vector like this
vector<vector int> A;
It works the same way as a 2d array
Welcome to C++! Your function my_2d_array has a couple of issues:
the return type is int, however you are attempting to return an array of ints.
the identifier of an array in C++ is actually a pointer to the first element of that array. Therefore, when you return 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::arrays from functions like you return ints or doubles.
std::arrays 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 ints 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.
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";
}
}
In my code I create a function outside of the main, which creates a 1D array and initializes to 0.
void create_grid(double *&y, int Npoints)
{
y = new double[Npoints];
for (int i = 0; i < Npoints; i++)
{
y[i] = 0;
}
}
If I didn't have the syntax of declaring in the function as double *&y I couldn't access the values of y.
I tried doing the same for a 2D array but i don't know the syntax. I tried &&**y and &*&*y but it didn't work. Does anyone know how to create a function outside of the main, which initializes a 2d dynamic array so I can use it in the main?
E.g.:
void create_grid_2D(double **&&y, int Npoints1, int Npoints2)
{
y = new double*[Npoints1];
for (int i = 0; i < Npoints1; i++)
{
y[i] = new double[Npoints2];
}
for (int i = 0; i < Npoints1; i++)
{
for (int j = 0; j < Npoints2; j++)
{
y[i][j] = 0;
}
}
}
int main()
{
int N = 10;
double **z;//correcting this line, i wrote z**
create_grid_2D(z, N, N);
delete[]z;
return 0;
}
C++ does not allow forming a pointer to reference or reference to reference. (And without a space between the characters, && is a single token meaning something entirely different.)
And your declaration double z**; is incorrect - you probably mean double **z;.
To write a function that takes the argument double **z by reference, you just want a reference to pointer to pointer:
void create_grid_2D(double **&y,int Npoints1,int Npoints2)
{
//...
}
Except don't use new and delete. Using them slightly wrong leads to memory leaks and bugs with dangling pointers and double deletes. For example, you tried to clean up your memory in main with delete []z;, but new-expressions were evaluated 11 times to your one delete-expression, so this misses out on deleting the row arrays z[0], z[1], ... z[9]. There's pretty much always a better and simpler way using std::unique_ptr, std::shared_ptr, std::vector, or other RAII (Resource Allocation Is Initialization) tools.
So I would change the function to:
void create_grid_2D(std::vector<std::vector<double>>& y,
unsigned int Npoints1,
unsigned int Npoints2)
{
y.assign(Npoints1, std::vector<double>(Npoints2, 0.0));
}
int main()
{
unsigned int N=10;
std::vector<std::vector<double>> z;
create_grid_2D(z, N, N);
// No manual cleanup necessary.
}
Or even use a return value rather than assigning an argument:
std::vector<std::vector<double>> create_grid_2D(
unsigned int Npoints1,
unsigned int Npoints2)
{
return std::vector<std::vector<double>>(
Npoints1, std::vector<double>(Npoints2, 0.0));
}
int main()
{
unsigned int N=10;
std::vector<std::vector<double>> z = create_grid_2D(N, N);
}
An easy trick to resolve/write such complicated references is (simplified version for the sake of this problem - it's a bit more complicated with braces present): start from the variable name and go to the left, step by step. In your case:
... y
y is ...
... & y
y is a reference ...
... *& y
y is a reference to a pointer ...
... **& y
y is a reference to a pointer to a pointer ...
double**& y
y is a reference to a pointer to a pointer to a double
So, the correct definition is:
void create_grid_2D(double**& y,int Npoints1,int Npoints2)
But as mentioned in the comments, please do really consider avoiding raw pointers in favor of std::vector and other standard containers.
So you want a reference on a pointer to a pointer.
2d pointer is int**, and the reference is int**&. That's what you want to use.
Then, you should a container or at least a smart pointer instead.
This approach would be a little different than what you currently have but basically you want a 2D grid and another name for this is simply a MxN Matrix! We can do this very easily with a simple template structure. This template class will hold all of the contents without having to put the data into dynamic memory directly. Then once you have your class object that you want to use we can then put that into dynamic memory with the use of smart pointers!
#include <iostream>
#include <memory>
template<class T, unsigned M, unsigned N>
class Matrix {
static const unsigned Row = M;
static const unsigned Col = N;
static const unsigned Size = Row * Col;
T data[Size] = {};
public:
Matrix() {};
Matrix( const T* dataIn ) {
fillMatrix( dataIn );
}
void fillMatrix( const T* dataIn );
void printMatrix() const;
};
template<class T, unsigned M, unsigned N>
void Matrix<T, M, N>::fillMatrix( const T* dataIn ) {
for ( unsigned i = 0; i < Size; i++ ) {
this->data[i] = dataIn[i];
}
}
template<class T, unsigned M, unsigned N>
void Matrix<T,M,N>::printMatrix() {
for ( unsigned i = 0; i < Row; i++ ) {
for ( unsigned j = 0; j < Col; j++ ) {
std::cout << this->data[i*Col + j] << " ";
}
std::cout << '\n';
}
}
int main() {
// our 1 day array of data
double data[6] = { 1,2,3,4,5,6 };
// create and print a MxN matrix - in memory still a 1 day array but represented as 2D array
Matrix<double,2,3> A;
A.fillMatrix( data );
A.printMatrix();
std::cout << '\n';
Matrix<double, 3,2> B( data );
B.printMatrix();
std::cout << '\n';
// Want this in dynamic memory? With shared_ptr the memory is handled for you
// and is cleaned up upon it's destruction. This helps to eliminate memory leaks
// and dangling pointers.
std::shared_ptr<Matrix<float,2,3>> pMatrix( new Matrix<float,2,3>( data ) );
pMatrix->printMatrix();
return 0;
}
Output:
1 2 3
4 5 6
1 2
3 4
5 6
1 2 3
4 5 6
The code below – it's a skeleton of a program operating on the dynamic collection of data. The idea is to use a structure containing two fields: the first stores the number of elements in collections, and the second is the actual collection (a dynamically allocated vector of ints). As you can see, the collection is filled with the required amount of pseudo-random data.
Unfortunately, the program requires completion, as the most important function.
Here's what i expect from the function:
if the collection is empty, it should allocate a one-element vector and store a new value in it.
if the collection is not empty, it should allocate a new vector with a length greater by one than the current vector, then copy all elements from the old vector to the new one, append a new value to the new vector and finally free up the old vector.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
struct Collection {
int elno;
int *elements;
};
void AddToCollection(Collection &col, int element) {
//the first part of the funtion
if (col.elno==0){
col.elements= new int[1];
col.elements[0]= element;
}
//this is the second part but i do not know how to do it.
//Please help me to complete***************
else {
int *temp;
temp = new[];
}
}
void PrintCollection(Collection col) {
cout << "[ ";
for(int i = 0; i < col.elno; i++)
cout << col.elements[i] << " ";
cout << "]" << endl;
}
int main(void) {
Collection collection = { 0, NULL };
int elems;
cout << "How many elements? ";
cin >> elems;
srand(time(NULL));
for(int i = 0; i < elems; i++)
AddToCollection(collection, rand() % 100 + 1);
PrintCollection(collection);
delete[] collection.elements;
return 0;
}
vector container is originally dynamic container. so u can use vector.
Just declare vector variable in structure and use it in AddToCollection function.
struct Collection {
int elno;
std::vector<int> elements;
};
void AddToCollection(Collection &col, int element) {
col.elements.push_back(element);
col.elno++;
}
like this.
Here is what you are looking for:
void AddToCollection(Collection &col, int element)
{
if(col.elements == NULL)
{
col.elements = new int[1];
col.elements[0] = element;
col.elno = 1;
}
else
{
int *newArr = new int[col.elno+1];
for(int i = 0; i < col.elno; i++)
{
newArr[i] = col.elements[i];
}
newArr[col.elno] = element;
delete[] col.elements;
col.elements = new int[col.elno+1];
for(int i = 0; i < col.elno+1; i++)
{
col.elements[i] = newArr[i];
}
delete[] newArr;
newArr = NULL; // avoid dangling pointer
col.elno++;
}
}
For sure using vector container is a great ideea but the exercise require no modification to the main function. The objective of this exercise is to help the student to understand dynamically allocated memory.
If i had an array of lets say 15 elements is there anyway for me to make it into a 2d array having it 5x3?
Or if i had a string with 15 letters would it be possible to make it into a 2d array having it 5x3?
This is what i have(using variables but using 5 as a and 3 as b in console)
void finishMap(string map, int a, int b)
{
string finalMap[a][b];
for(int i = 0; b>i; i++)
{
for(int x = 0; a>x; x++)
{
finalMap[a][b] += {{map[x]}, {i}};
}
}
}
Also pretty new to c++ so if you see anything i shouldn't be please tell me :3
I'm using char arrays (c strings) in my answer because I think they are useful to illustrate how arrays work - and thre really isn't a point in using std::string in your case. std::string hides a lot of the underlying nuts and bolts so I would generally recommend to play around with C strings first to understand how std::string works. Also, check out this tutorial: http://www.cplusplus.com/doc/tutorial/arrays/
A 2-dimensional array has the same memory layout as a 1-d array. In terms of memory layout, char[3][5] is the same as char[3*5] is the same as char[15]. You can use a 1-d array as a 2-d array using char[column+row*width]. The only difference if you use subscripts is that the compiler remembers how many dimensions there are and will do the whole column+row*width calculation for you.
Take this example:
char temp[5] = "abcd"; //need 5 for string termination char `\0`
for(int i = 0; i < 4; ++i) {
std::cout << temp[i];
}
std::cout << "\n\n";
for(int i = 0; i < 2; ++i) {
for(int j = 0; j < 2; ++j) {
std::cout << temp[j+2*i];
}
std::cout << std::endl;
}
Will print:
abcd
ab
cd
You can always access an array in strides. Here's a possible example using templates to restride a 1D array as a 2D array:
template <typename T, unsigned int N1, unsigned int N2>
struct strider
{
using array_type = T[N1 * N2];
array_type & data_;
Strider(array_type & data) : data_(data) {}
T & operator()(std::size_t i1, std::size_t i2)
{
return data_[i1 * N2 + i2];
}
};
template <unsigned int N1, unsigned int N2, T>
strider<T, N1, N2> stride(T (&a)[N1, N2]) { return {a}; }
Usage:
int a[15] = {};
strider<int, 3, 5> s(a);
s(1, 2) = 20;
assert(a[7] == 20);
stride<5, 3>(a)(4, 2) = 10;
assert(a[14] == 10);
I've overloaded operator() for the strided access, since unlike operator[] it can have arbirary signatures.
With some more work you could make the rank of the strided view variadic.
Okey so i used something a bit different then what i mentioned. What i did was have the user enter 3 lines of 5 length letters, which i figured out how to add into the 2d array. If your having the same issue as me, heres my code:
int main()
{
string path;
int a, b;
cin >> a >> b;
string finalMap[a][b];
for(int i = 0; b>i; i++){
cin >> path;
for(int x = 0; a>x; x++){
finalMap[x][i] = (path[x]);
}
}
for(int x = 0; b>x; x++)
{
for(int y = 0; a>y; y++)
{
cout << finalMap[y][x];
}
cout << endl;
}
return 0;
}
Thanks for trying tho, really appreciate it ^.-
You can try to use reinterpret_cast. Complete example:
#include <iostream>
using namespace std;
typedef char mtrx[5][3];
int main(){
char data[15] = "Some String";
mtrx &m = *reinterpret_cast<mtrx*>(&data);
m[1][2] = '*';
cout << data << endl;
return 0;
}
don't know why but i get an error: after this structure i can't index the matrix, so i cant use the "indexing method" over the defined matrix.Can anyone tell me why? or how to fix it?
Header:
const int days=31;
const int exp=6;
struct Array{
int days;
int exp;
int **M;
};
Constuctor:
void constr(Array loc){
//Construct of 31*6 Matrix, were 31 nr. of days and 6 specific types:
//0-HouseKeeping, 1-Food, 2-Transport, 3-Clothing, 4-TelNet, 5-others
loc.days = days;
loc.exp = exp;
loc.M = new int*[loc.days];
for(int i=0; i<loc.days;i++ ){
loc.M[i] = new int[loc.exp];
for (int j = 0; j< loc.exp; j++){
loc.M[i][j] = 0;
}
}
}
Controller.cpp
void add(int cant,int tip, Array M){
//Adds to current day the amount to a specific type
currDay();
M[currentDay][tip] += cant; ////////////error
}
void insert(int zi,int tip,int cant, Array M){
//Adds to current day the amount to a specific type
M[zi][tip] = cant; ///////////error
}
void removeDay(int day, Array M){
for(int i = 0; i<6; i++)
M[day][i] = 0; ///////////error
//zi and tip ~ day type... for easier read.
//i need to manage the expenses of a family in a month doesn't matter which
ERROR: error: no match for 'operator[]'
UI(where constructor is used):
int main(){
Array M;
constr(M);
printMenu();
return 0;
}
You're not accessing the member:
M.M[currentDay][tip]
instead of
M[currentDay][tip]
Or you could define operator [] for your struct:
struct Array{
int days;
int exp;
int **M;
int*& operator[] (int idx) { return M[idx]; }
};
You are trying to call operator[] on the type array. You need to get the pointer member first.
M.M[day][i];
That said: You are not writing C++ but some obscure form of bad C. You might want to have a look at the book list and read one of them before pursuing coding any further.
You have at least two problems:
The first is that you are using the actual structure as the array, which wont work. Use e.g. M.M[day][i].
The second is that when you create the array, you pass the structure by value, this means it will be copied to a local variable in the constr function and the data will not be available in the function calling constr. Pass it as a reference instead, i.e. void constr(Array &loc).
The second problem can also be solved by using a constructor in the structure, instead of a separate function:
const int DAYS=31;
const int EXP=6;
struct Array{
int days;
int exp;
int **M;
// Constructor, called when an instance of structure/class is created
Array(){
days = DAYS;
exp = EXP;
M = new int*[days];
for(int i=0; i<days;i++ ){
M[i] = new int[exp];
for (int j = 0; j< exp; j++){
M[i][j] = 0;
}
}
}
// Destructor, called when structure/class is destroyed
~Array(){
if(M){
for(int i=0;i<days;i++){
if(M[i])
delete [] M[i];
}
delete [] M
}
}
// Copy constructor, called when instance of structure/class is copied
Array(const Array &array){
days = array.days;
exp = array.exp;
M = new int*[days];
for(int i=0; i<days;i++ ){
M[i] = new int[exp];
for (int j = 0; j< exp; j++){
M[i][j] = array.M[i][j];
}
}
}
};