This is an extension to a previous question I previously asked. I can use a template to submit a dynamic 2D array and access the elements. Now, let's say I have a pointer to such an array. I am currently using the method shown here to assign my pointer to the original 2d array. I initially thought I could just change the expected input of the template function to (*A)[M][N] but that's a no-go. Am I missing some concept regarding pointers that someone could kindly explain?
header.h
#pragma once
#include <cstddef>
#include <iostream>
using namespace std;
template<size_t N, size_t M>
void printPtr( int(*A)[M][N]) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << A[i][j] << " ";
}
cout << endl;
}
}
main.cpp
#include "header.h"
#include <iostream>
using namespace std;
int main() {
int A[][3] = {
{1,2,3},
{4,5,6},
{7,8,9},
{10,11,12}
};
int (*ptrA)[3] = A;
printPtr(ptrA);
}
If you're not interested in knowing why your code isn't working in the first place just skip to the end of this post
The problem with your code is that you're "simulating" an array decaying by passing your pointer along:
int A[][2] = {
{1,2,3},
{4,5,6},
{7,8,9},
{10,11,12}
};
int (*ptrA)[3] = A;
This is confirmed by the following code which uses C++11 features:
#include <iostream>
#include <type_traits>
using namespace std;
template <typename T, typename U>
struct decay_equiv :
std::is_same<typename std::decay<T>::type, U>::type
{};
int main() {
int A[][4] = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 },
{ 10, 11, 12 }
};
std::cout << std::boolalpha
<< decay_equiv<decltype(A), int(*)[3]>::value << '\n'; // Prints "true"
}
Example
You should either pass a non-decayed type (i.e. a type that has all the information regarding the array dimension) to the function via a pointer or a reference:
#include <cstddef>
#include <iostream>
using namespace std;
template<size_t N, size_t M>
void printPtr(int (*A)[M][N] /* Also a reference could work */) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << (*A)[i][j] << " ";
}
cout << endl;
}
}
int main() {
int A[][6] = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 },
{ 10, 11, 12 }
};
int(*ptrA)[4][7] = &A; // Not a decayed type
printPtr(ptrA);
}
Example
Another solution would be to not use a pointer to the array in the first place or dereference it when passing a reference to the array:
template<size_t N, size_t M>
void printPtr( int(&A)[M][N]) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << A[i][j] << " ";
}
cout << endl;
}
}
...
printPtr(A);
printPtr(*ptrA);
Example
You defined the function parameter as a pointer to a two-dimensional array
int(*A)[M][N])
while are trying to call the function passing as the argument a pointer to a one-dimensional array
int (*ptrA)[3] = A;
printPtr(ptrA);
Moreover the function itself is invalid. It shall look like
template<size_t N, size_t M>
void printPtr( int(*A)[M][N]) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << ( *A )[i][j] << " ";
}
cout << endl;
}
}
that is you have to use expression ( *A )[i][j] instead of A[i][j]
So you need to change the function the way shown above and to use appropriate pointer as the argument
int (*ptrA)[4][3] = &A;
printPtr(ptrA);
Of course it would be better to define the function parameter as reference to a two-dimensional array. For example
template<size_t N, size_t M>
void printPtr( int(&A)[M][N]) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << A[i][j] << " ";
}
cout << endl;
}
}
In this case you could call the function like
printPtr( A );
It should be
template<size_t N, size_t M>
void printPtr(const int(&A)[M][N]) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << A[i][j] << " ";
}
cout << endl;
}
}
calling with:
printPtr(A);
or
template<size_t N, size_t M>
void printPtr(const int(*A)[M][N]) {
for(int i=0; i < M; i++){
for(int j=0; j<N; j++) {
cout << (*A)[i][j] << " ";
}
cout << endl;
}
}
calling with:
printPtr(&A);
BTW your pointer should be:
int (*ptrA)[4][3] = &A;
Related
I need som help outputting the content of this multidimensional array. I'm trying pass the address of the array to the function and let it grab and run thru it.
#include <iostream>
using namespace std;
void LoopDeLoop(int[][] *arr)
{
for(int k = 0; k < 3; k++)
{
for(int j = 0; j < 4; j++)
{
cout << arr[k][j];
}
}
}
int main() {
int arr[3][4] = { {1,2,3,4}, {5,6,7,8}, {10,11,12,13} };
LoopDeLoop(&arr);
return 0;
}
This pattern you are trying to use is old fashioned C.
Modern C++ way to do it should be more clear for you:
#include <array>
#include <iostream>
using MyArray = std::array<std::array<int, 4>, 3>;
void LoopDeLoop(const MyArray& arr)
{
for (auto& row : arr) {
for (auto x : row) {
std::cout << x << ' ';
}
std::cout << '\n';
}
}
int main()
{
MyArray arr { std::array { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 10, 11, 12, 13 } };
LoopDeLoop(arr);
return 0;
}
https://godbolt.org/z/Mbcjf9bx5
C++ allows to pass plain array by reference and also automatically deduce dimensions using templates:
Try it online!
#include <iostream>
using namespace std;
template <int Rows, int Cols>
void LoopDeLoop(int const (& arr)[Rows][Cols])
{
for(int k = 0; k < Rows; k++)
{
for(int j = 0; j < Cols; j++)
{
cout << arr[k][j];
}
}
}
int main() {
int arr[3][4] = { {1,2,3,4}, {5,6,7,8}, {10,11,12,13} };
LoopDeLoop(arr);
return 0;
}
Output:
1234567810111213
My code works when put in the int main() function but when I implement it as another function (void bubbleSort) the output displays it as if there was no sorting done.
void bubbleSort(int numeros[])
{
int store = 0;
int length = ARRAY_SIZE(numeros);
for(int i=0; i<(length-1); i++)
{
for(int j=0; j<(length-i-1); j++)
{
if(numeros[j] < numeros[j+1])
{
store = numeros[j];
numeros[j] = numeros[j+1];
numeros[j+1] = store;
}
}
}
for(int m=0; m<1000; m++)
{
cout << numeros[m] <<' ';
}
}
What could I have possibly done wrong? Any help would be greatly appreciated.
You can't pass a full array as an argument to a c++ function, only a pointer to the first element in the array. As a result you need some way to tell the function how long the array is. One way it to pass that in as another argument (as shown below). There is some discussion and suggestions of other/better ways to do it here.
For example if you accidentally pass in the wrong length argument to these functions they will start operating on whatever memory exists after the block of memory where your array is.
#include <iostream>
using namespace std;
void printArray(int array[], int length) {
for(int i=0; i<length; i++) {
cout << array[i] << " ";
}
cout << endl;
}
void bubbleSort(int numeros[], int length) {
int store = 0;
for(int i=0; i<(length-1); i++) {
for(int j=0; j<(length-i-1); j++) {
if(numeros[j] < numeros[j+1]) {
store = numeros[j];
numeros[j] = numeros[j+1];
numeros[j+1] = store;
}
}
}
cout << "array at end of bubble sort: ";
printArray(numeros, length);
}
int main() {
int anArray[] = {1, 3, 2, 4, 6, 5, 10, 9, 7, 8};
int arraySize = sizeof(anArray)/sizeof(anArray[0]);
cout << "arraySize: " << arraySize << endl;
cout << "array before sort: ";
printArray(anArray, arraySize);
bubbleSort(anArray, arraySize);
cout << "array after sort: ";
printArray(anArray, arraySize);
return 0;
}
I wrote a following code:
#include <iostream>
#include <vector>
#include <iomanip>
using std::cin; using std::cout; using std::endl;
int DivideTwoFactorials(int m, int n)
{
int div(1);
while (m > n)
{
div *= m;
m--;
}
return div;
}
int Factorial(int m)
{
int fact(1);
for (int i(1); i <=m; i++) fact *= i;
return fact;
}
int BinomialCoefficient(int m, int n)
{
return (DivideTwoFactorials(m, n) * (1./Factorial(m-n)));
}
template <typename Type>
void Modify3DContainer(Type &a, int fun(int, int), int p = 0, int q = 0)
{
int m(a.size());
int n(a[0].size());
int z(a[0][0].size());
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < z; k++)
{
if (a[i][j][k] == fun(p, q)) a[i][j][k] = a[i][j][k] * a[i][j][k];
}
}
}
}
int main()
{
cout << endl << "Input dimensions of 3D container: ";
int m, n, p;
cin >> m >> n >> p;
std::vector<std::vector<std::vector<int>>> a(m, std::vector<std::vector<int>>(n, std::vector<int>(p)));
cout << endl << "Input elements of 3D container: ";
int x;
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < p; k++)
{
cin >> x;
a[i][j][k] = x;
}
}
}
Modify3DContainer(a, BinomialCoefficient, 6, 4);
cout << endl << "Modified 3D container: " << endl << endl;
for (int i(0); i < m; i++)
{
for (int j(0); j < n; j++)
{
for (int k(0); k < p; k++)
{
cout << std::setw(6) << a[i][j][k];
}
cout << endl;
}
cout << endl;
}
return 0;
}
There is one issue regarding the function "Modify3DContainer" which accepts the following parameters:
a reference on a 3D container
a function that returns an int and receives two int parameters
two int parameters with default value 0.
The function is supposed to find all elements in the 3D container that are equal to return value of function defined by the second parameter when that function receives p and q as parameters, and substitute those elements with their square value.
The problem here is that function "Modify3DContainer" accepts multiple types of containers and I am not allowed to pass dimensions of the container to said function (c++ programming assignment). The function currently works only for vector of vectors of vectors by using the size() method, but it will not work for regular arrays. I tried using the sizeof operator, but it doesn't work on multidimensional vectors. Checking the type of the container with typeid could be one possible solution, but there are many combinations to check since the 3D container could, for example, be vector of vectors of deques etc.
So my question is, is there a way to find the size of passed 3D container, no matter its type?
Thank you.
If you really want to know the size then what you are looking for is std::size. It will tell you the size of anything passed to it that is a raw array or an object that has a size member function. Unfortunately it is a C++17 feature so you might not have it available in the compiler you are using.
Fortunately the mechanics for it already exist in the current standard so we can write our own like the possible implementation provided at previous link
template <class C>
constexpr auto size(const C& c) -> decltype(c.size())
{
return c.size();
}
template <class T, std::size_t N>
constexpr auto size(const T (&array)[N]) noexcept
{
return N;
}
And using them in something like
int main()
{
std::vector<std::vector<std::vector<int>>> vec(10, std::vector<std::vector<int>>(20, std::vector<int>(30, 0)));
int arr[10][20][30];
std::cout << size(vec) << "\t" << size(arr) << "\n";
std::cout << size(vec[0]) << "\t" << size(arr[0]) << "\n";
std::cout << size(vec[0][0]) << "\t" << size(arr[0][0]) << "\n";
return 0;
}
We get
10 10
20 20
30 30
Live Example
If you do not need the size but just need to loop then you can use a range based for loop or a regular loop and use std::begin and std::end which works with containers and arrays.
here I have a problem. I want to manipulate the following Matrix
Matrix A =
1---------2----------3
4---------5----------6
7---------8----------9
into
7---------8----------9
4---------5----------6
1---------2----------3
#include<iostream>
using namespace std;
void f(int ArrayName, int Size);
int main()
{
int x[3][3]={{1,2,3}, {4, 5,6},{7,8,9}};
f(x, 3);
system("pause");
}
void f(int ArrayName, int Size)
{
int holder;
for(int i=0; i<Size; i++){
for(int j=0; j<Size; j++)
{
holder=ArrayName[i][j];
ArrayName[i][j]=ArrayName[i+2][j+2];
ArrayName[i+2][j+2]=holder;
}
}
for(int k=0; k<Size; k++)
for(int l=0; l<Size; l++)
{
cout<<ArrayName[k][l];
if(l=3) cout<<"\n";
}
}
Errors:
E:\Semester 2\CPrograms\Array2.cpp In function `int main()':
10 E:\Semester 2\CPrograms\Array2.cpp invalid conversion from `int (*)[3][3]' to `int'
10 E:\Semester 2\CPrograms\Array2.cpp initializing argument 1 of `void f(int, int)'
E:\Semester 2\CPrograms\Array2.cpp In function `void f(int, int)':
22 E:\Semester 2\CPrograms\Array2.cpp invalid types `int[int]' for array subscript
(Last error repeated for five times)
All is done before us.:)
You can do quickly the assignment using standard algorithm std::reverse declared in header <algorithm>
For example
#include <iostream>
#include <algorithm>
#include <iterator>
int main()
{
int a[3][3] =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
for ( const auto &row : a )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
std::reverse( std::begin( a ), std::end( a ) );
for ( const auto &row : a )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The program output is
1 2 3
4 5 6
7 8 9
7 8 9
4 5 6
1 2 3
As for your code then already this function declaration
void f(int ArrayName, int Size);
is wrong.
The first parameter should be either a reference to the array or a pointer to its first element.
For example
void f( int ( &ArrayName )[3][3] );
or
void f( int ( *ArrayName )[3], int Size );
If you want to write the function yourself then it can look the following way
#include <iostream>
void reverse( int ( *ArrayName )[3], size_t Size )
{
for ( size_t i = 0; i < Size / 2; i++ )
{
for ( size_t j = 0; j < 3; j++ )
{
int tmp = ArrayName[i][j];
ArrayName[i][j] = ArrayName[Size - i - 1][j];
ArrayName[Size - i - 1][j] = tmp;
}
}
}
int main()
{
int a[3][3] =
{
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
};
for ( const auto &row : a )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
std::cout << std::endl;
::reverse( a, 3 );
for ( const auto &row : a )
{
for ( int x : row ) std::cout << x << ' ';
std::cout << std::endl;
}
return 0;
}
The program output will be the same as above.
The prototype and declaration of your function should be :
void f(int ArrayName[][3], int Size)
Modify the code as:
#include<iostream>
using namespace std;
void f(int ArrayName[][3], int Size); //change here
int main()
{
int x[3][3]={{1,2,3}, {4, 5,6},{7,8,9}};
f(x, 3);
system("pause");
}
void f(int ArrayName[][3], int Size) //change here
{
int holder;
for(int i=0; i<Size/2; i++){ //change here
for(int j=0; j<Size; j++)
{
holder=ArrayName[i][j];
ArrayName[i][j]=ArrayName[size-i-1][size-i-1]; //change here
ArrayName[size-i-1][size-i-1]=holder; //change here
}
}
Try the solution in the code below. It uses the matrix as a vector, but has no dimension dependencies in the f() function prototype.
You have some errors in your code:
The array x[][] has to be passed by reference/pointer and not by value, then the function f() has to receive a pointer (or a reference) to int and not an int!
The for-loop scanning the matrix rows doesn't have to be for(int i=0; i<Size; i++), but for(int i=0; i<Size/2; i++). Using i<Size you swaps two times all the rows and then it seems nothing happens!
The following code:
ArrayName[i][j]=ArrayName[i+2][j+2];
ArrayName[i+2][j+2]=holder;
should be:
ArrayName[i][j]=ArrayName[Size-i-1][j];
ArrayName[Size-i-1][j]=holder;
The following code:
if(l=3) cout<<"\n";
l=3 assigns a value, don't do a comparison.
It should be:
if(l==Size-1) cout<<"\n";
#include<iostream>
using namespace std;
void f(int * ArrayName, int Size);
int main()
{
static const int Size=4;
int x[Size][Size];
//Loads the numbes into the matrix
for(int i=0;i<Size;i++)
for(int j=0;j<Size;j++)
x[i][j]=i*Size+j+1;
f(&x[0][0], Size);
}
void f(int *ArrayName, int Size)
{
int holder;
cout << "Input\n";
for(int k=0; k<Size; k++) {
for(int l=0; l<Size; l++)
cout<<ArrayName[k*Size+l]<<" ";
cout << "\n";
}
// Elaborate the matrix
// ----------------------------------------
for(int i=0; i<Size / 2; i++){
for(int j=0; j<Size; j++) {
holder=ArrayName[i*Size+j];
ArrayName[i*Size+j]=ArrayName[(Size-i-1)*Size+j];
ArrayName[(Size-i-1)*Size+j]=holder;
}
}
// ----------------------------------------
cout << "----------\n" << "Output\n";
for(int k=0; k<Size; k++) {
for(int l=0; l<Size; l++)
cout<<ArrayName[k*Size+l]<<" ";
cout << "\n";
}
}
I have created a 3d array into main function because one of its size came from used input. I am using C++
std::cin >> size;
typedef int T[8][3];
T* tables = new T[size];
It is basically tables[size][8][3]
Now I have to use this 3d table in different functions and have to store values into it. The best way to do it by make this table as a global variable. But I am not sure that I can do it after main function. The other option I have, that I have to pass this table as a parameter and have to return that at the end of the function.
I have tried both the approach but I am having error. Please help me about this issue. I don't know which approach to choose and how to do it.
Thank you in advance.
**Example:**This an example what I really want to do. Here I create a 3d array in main function and through another function I gave some input into that array and again print that in main function.
#include <iostream>
#include <conio.h>
using namespace std;
class M
{
public:
int i,j,k;
public:
int pass(int (*table)[8][3],int size);
}
int M:: pass(int (*table)[8][3],int s)
{
for (i=0;i<s;i++)
{
//int a = tables[i][2][1];
for(j=0;j<8;j++)
{
for(k=0;k<3;k++)
{
table[i][j][k]=i;
}
}
}
return (*table)[8][3]; // not sure about this
}
int main()
{
int size,i,j,k;
std::cin >> size;
typedef int T[8][3]; // T is your 2d array type
T* tables = new T[size];
cout << "test";
M mx;
mx.pass(tables,size); // not sure
for (i=0;i<size;i++)
{
for(j=0;j<8;j++)
{
for(k=0;k<3;k++)
{
cout<<tables[i][j][k];
cout<<" ";
}
cout<<endl;
}
cout<<endl;
cout<<"..........." << i <<endl;
}
getch();
}
I don't know if I completely understand your problem. But you can definitely store the pointer locally in your object and reference it elsewhere. Something like this:
class M
{
public:
M(int(*tbl)[8][3]) : table(tbl) { }
int(*table)[8][3];
int i, j, k;
public:
void pass(int size);
};
void M::pass(int s)
{
for (i = 0; i<s; i++)
{
for (j = 0; j<8; j++)
{
for (k = 0; k<3; k++)
{
table[i][j][k] = i;
}
}
}
}
int main()
{
int size, i, j, k;
std::cin >> size;
typedef int T[8][3]; // T is your 2d array type
T* tables = new T[size];
cout << "test";
M mx(tables);
mx.pass(size); // not sure
for (i = 0; i<size; i++)
{
for (j = 0; j<8; j++)
{
for (k = 0; k<3; k++)
{
cout << tables[i][j][k];
// or you can also:
// cout << mx.table[i][j][k];
cout << " ";
}
cout << endl;
}
cout << endl;
cout << "..........." << i << endl;
}
_getch();
}
Since you are creating a dynamic 3D array whose two dimensions are fixed, Use a std::array<std::array<int, 3>, 8> as your 2D array. Use a std::vector<__2D_ARRAY_TYPE> to create the 3D array.
#include <iostream>
#include <array>
#include <vector>
int main() {
std::array<std::array<int, 3>, 8> array_2d ;
std::vector<decltype(array_2d)> array_3d ;
int size = 4 ;
for(int i = 0; i < size; ++i)
{
for(int j = 0; j < 8; ++j)
for(int k = 0; k < 3; ++k)
array_2d[j][k] = j + k ;
array_3d.push_back(array_2d);
}
return 0;
}
Something like this you can use easily which does the job more easily without any manual memory management.
You can pass it to a function. The signature would be :
return_type function_name(const std::vector<std::array<std::array<int, 3>, 8>>& array_3d)
{ .... }
In
class M
{
public:
int i,j,k;
public:
int pass(int (*table)[8][3],int size);
}
you don't have to write public twice. You can simply put all of the public member data under the keyword public.
Also, you seem to be re-writing your function over again at the very end. Instead of
cout<<tables[i][j][k];
You can write
cout<<*tables