I was trying to dig more into using arrays and pointers while I came across this problem:
main.cpp:13:7: error: cannot convert 'int [2][5][10]' to 'int*'
in assignment show=ary;
Here's the code:
#include <iostream>
using namespace std;
void arrayLearn(int *);
int main()
{
int ary[2][5][10];
int *show;
ary[2][4][9]=263;
ary[2][5][10]=100;
show=ary; //line 13
arrayLearn(show); //line 14
cout <<"End process"<<endl;
return 0;
}
void arrayLearn(int *arg)
{
for(int i=0;i<100;i++)
{
cout<<"Pointer position: "<<i<<" Value: "<<*(arg++)<<endl;
}
}
If I remove the line 13 and replace line 14 with the following code,
arrayLearn(ary[5][10]);
then the program compiles, but I don't understand why I should pass only two dimensions and not three. If I'm passing the pointer to the first item in the array then why can't I just pass the pointer like this?
arrayLearn(ary);
Please let me know if I've missed some vital concepts or failed to see a really simple mistake.
As Abhishek stated, you are trying to pass a 3-dimensional array to a 1-dimensional object.
If the show variable is not used anywhere else, you can do the following:
#include <iostream>
using namespace std;
void arrayLearn(int *);
int main()
{
int ary[2][5][10];
// Code change explained below (see Note)
ary[1][4][8] = 263;
ary[1][4][9] = 100;
// Pass the starting address of the array
arrayLearn(&ary[0][0][0]);
cout <<"End process"<<endl;
return 0;
}
// Iterate through the array using the position of the elements in memory
void arrayLearn(int *arg)
{
for(int i=0;i<=100;i++)
{
cout<<"Pointer position: "<<i<<" Value: "<<*(arg++)<<endl;
}
}
Output:
...
Pointer position: 98 value: 263
Pointer position: 99 value: 100
End process
This way allows you to pass the starting address of the array to the function.
Note: It should be noted that your original array assignments ary[2][4][9] = 263; and ary[2][5][10] = 100; are outside the bounds of the array. Array indexes start at 0. So even though you have declared your array as ary[2][5][10]; To access the last array element, you would use ary[1][4][9];.
If you are willing to use std::vector, which I highly recommend, you can use the following code to create a 2D vector:
using std::vector<int> Vec1;
using std::vector<Vec1> Vec2;
using std::vector<Vec2> Vec3;
Vec3 a(2, Vec2(5, Vec1(10, 0));
and then change the argument of arrayLearn to const Vec3& to call it using a.
void arrayLearn(const Vec3& arg)
{
// You'll need to use three loops to traverse all the elements.
for ( auto const& v2 : arg )
{
for ( auto const& v1 : v2 )
{
for ( auto const& item : v1 )
{
// Use item
}
}
}
}
In simple terms, ary is 3-Dimensional and show is 1-Dimensional. The compilation errors tell you that you can't convert 3D into 1D. Now, why does following work?
arrayLearn(ary[5][10]);
It is because, ary[5][10] is referring to 1D (a row or a column or a height, depends on how you visualize 3D array) and arrayLearn is also accepting 1D parameter.
if you want to pass ary using show then pass 2D like ary[5][10] to show variable, something like following :)
show = ary[5][10];
you can use STL data structurs like vector, map , linkedlist , ...
that all of them are better that array both in emplementation and in performance.
but for solving exactly this problem, you must pass 3 dimention array to one function in this manner:
int array[10][7][8];
void function_sample(int (*a)[7][8] , int length)
{
//for example for printing array cells
for(int i =0 ; i< length ; i++)
{
for(int j =0 ; j< 7 ; j++)
{
for(int k =0 ; k< 8 ; k++)
{
cout << a[i][j][k] << endl
}
}
}
//....
}
and for calling this function :
int array[10][7][8] //= {initial your array};
function_sample(array , 10);
Related
I'm learning C++ (reasonably confident in JavaScript) and I can't find a C++ equivalent to the JS array.length;. I want a simple way to loop through an array based on the array length?
I have followed a number of tutorials but all seam to require the array length to be manually stated in the for loop (or pushed into the function)?
Below code gets an error and adding the #include causes a compiler error (DEV++).
Is there a C++ or reason why there is no simple call of the array length?
#include <iostream>
using namespace std;
int main () {
int shoppingList [3] = {1, 2, 3};
for (int i=0; i < shoppingList.size(); i++) {
cout << shoppingList[i] << endl;
}
}
For a C-style array like you have you can use range-based for loops:
for (int value : shoppingList)
{
std::cout << value << '\n';
}
As for getting the number of elements from an array, there's a "trick": You know the size of the array itself, and you know the size of each element in the array. That means if you divide the size of the array with the size of each element, you will get the number of elements.
In short
size_t numberElements = sizeof shoppingList / sizeof shoppingList[0];
Important note: This "trick" only works with actual arrays! Once an array have decayed to a pointer (to its first element, which often happens) all you're left with is the pointer. There's no way to get the size of the memory it points to, and this "trick" can not be used.
And as mentioned in my comment, the "best" solution is to use either std::array or std::vector.
Built-in types don’t have member functions with C++. However, there is a non-member std::size(array) function:
for (std::size_t i{}; i != std::size(shoppingList); ++i) {
// ...
}
Note that the counter is usinf std::size_t to match the signedness of the result of std::size(...). Also, do not use the sizeof hack suggested in other answers: it is a trap! The cde will happily compile when passing pointers to it but it will also produce the wrong result.
Of course, the idiomatic way to iterate over a range in C++, including arrays, is (assuming you only need the values and not their position):
for (int val: shoppingList) {
// ...
}
Array doesn't have a direct size() member function, you can find the size of an array like this int size = sizeof(arr)/sizeof(arr[0]); and use it in the for loop.
#include <iostream>
using namespace std;
int main () {
int shoppingList [3] = {1, 2, 3};
int size = sizeof(shoppingList)/sizeof(shoppingList[0]);
for (int i=0; i < size(); i++) {
cout << shoppingList[i] << endl;
}
}
You can do something like, sizeof(A)/sizeof(A[0]). This would give you the total number of elements in the array.
Let's take an example A = {1,2,3,4,5} // all ints
If you evaluate sizeof(A)/sizeof(A[0]), it would give you 5 and as you see, you would not need to manually enter the size of the array.
Hope this helps. :)
#include <iostream>
using namespace std;
int main()
{
A = {1,2,3,4,5};
for (int i = 0; i< sizeof(A)/sizeof(A[0]); i++)
//whatever you want to do with this
return 1;
}
I am working on a paint program and i create an array of figures in a class
and i want to pass that array to another class and loop through it's elements
i dont understand the problem
the main class:
CFigure* FigureList[Figcount];
CFigure* getfiglist()
{
return *FigureList;
}`
and the other class include:
CFigure *P=pManager->Getfiglist();
for(int i=0;i<pManager->Getfigcount;i++)
{
*(p+i)->resize(factor); //displays error : operand of * must be a pointer
}
how should i access the array elements using the passed pointer and what did i do here that caused the error . thanks in advance
There is a lot to say about arrays in C++, here is some information that might help :
Native C++ arrays
if you create an array like so :
int array[10] = {0,1,2,3,4,5,6,7,8,9};
And you try to print the values of array, &array or &array[0] you will notice they are all the same values. This value is the adress of the first element in your array. There is no such thing as an array pointer, there is just a pointer to the first element.
As the other elements of your array follow the first, you can access them by adding 1 to the address of the first element (array+1) :
void print(int *array, int length)
{
for (int i=0 ; i<length ; i++){
cout << *(array+i) << endl;
}
}
int main()
{
int array[10] = {0,1,2,3,4,5,6,7,8,9};
print(array, 10);
}
It turns out that you can also use the regular expression to access your array elements and it will work fine :
void print(int *array, int length)
{
for (int i=0 ; i<length ; i++){
cout << array[i] << endl;
}
}
Vectors
That being said, if one is not careful with native arrays, the code may quickly get very nasty and hard to read... This is why you should use std::vector instead as suggested by #Ðаn.
Vectors have the particularity to be dynamic so you don't have to specify any size when you create them, and you can add as many elements as you want without caring about any pointer or memory stuff.
void print(vector<int> &v)
{
for (int i=0 ; i<v.size() ; i++){
cout << v[i] << endl;
}
}
int main()
{
vector<int> v = {0,1,2,3,4,5,6,7,8,9};
v.push_back(10);
v.push_back(11);
v.push_back(12);
print(v);
}
Links
You can read more about vectors here.
I didn't talk about it but there is also std::array.
I'm new to c++ and I've spent a night thinking about this. I want to create a 2 dimensional array, length of first dimensional is given. Length of second dimensional, is increased from 1. e.g. for 2d array a[][], a[0][] has 1 element, a[1][] has 2 elements, a[2][] has 3 elements, etc.
It doesn't sound like a hard structure, but I can't find a two to create it - all I can do is to create a x * x array which means half of the space is wasted for me.
Anyone has any idea? Thanks in advance.
std::vector solution:
vector< vector<int> > stairs;
for(int i = 0; i < n; i++) // n is size of your array
stairs[i].resize(i+1);
You can also do this using plain pointers:
int * stairs[n];
for(int i = 0; i < n ; i++)
stairs[i] = new int[i+1];
But this time you will have to worry about deleting this structure when it is no longer needed.
Try considering dynamic allocation for your array.
Dynamic array allocation
Another way to make multi dimensional arrays is using a concept known
as pointer to pointers. Like Ron was saying on thursday, most of think
of a 2D array like a spreadsheet with rows and columns (which is just
fine), but 'under the hood', C++ is using ptr to ptrs. First, you
start off with creating a base pointer. Next, allocate an array of row
pointers and assign the address of the first one to the base pointer.
Next, allocate memory to hold each rows column data and assign the
address in the row pointer array
But if you're new to CPP, I assume that you won't be dealing with a large number of data so don't worry about memory !
One solution is to define a class that holds a single dimensional data array of size x*(x+1)/2, and overload type & operator()(int r, int c) to do the right type of indexing.
template<class datatype, int size>
class strange2dArray {
datatype data[size*(size+1)/2];
datatype & operator()(int r, int c) {
// assert if the indexes are correct
return data[r*(r+1)/2+c];
}
};
BTW, unless you're doing this for learning C++, you should probably use some kind of math library (or whatever) to provide you with such elementary data structures. They'll implement it much more efficiently and safely.
First let's see a test of Python:
>>> a=[]
>>> a[0]=3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list assignment index out of range
>>> a={}
>>> a[0]=3
Oops, looks like array, does't means it is array. If you want dynamic size of "array", you can use mapping.
Yes, it is the first solution:
#include <map>
#include <iostream>
using namespace std;
typedef std::map<int, int> array_d2; //length of second dimensional is increased
array_d2 myArray[10] ; //length of first dimensional is given
int main()
{
myArray[0][1] = 3;
myArray[0][2] = 311;
//following are tests
cout << myArray[0][1] << endl;
cout << myArray[0][2] << endl;
return 0;
}
(output is:)
$ ./test
3
311
My second solution is to use , something more like a array , but have the resize capability, you should override the opertation [] to make it automatically for user.
#include <vector>
#include <iostream>
using namespace std;
//length of second dimensional is increased
class array_d2 {
int m_size;
vector<int> m_vector;
public:
array_d2 (int size=10) {
m_size = size;
m_vector.resize(m_size);
};
int& operator[] ( int index ) {
if (index >= m_size) {
m_size = index + 1;
m_vector.resize(m_size);
}
return m_vector[index];
};
};
array_d2 myArray[10] ; //length of first dimensional is given
int main()
{
myArray[0][1] = 3;
myArray[0][20] = 311;
myArray[1][11] = 4;
myArray[1][12] = 411;
//following are tests
cout << myArray[0][1] << endl;
cout << myArray[0][20] << endl;
cout << myArray[1][11] << endl;
cout << myArray[1][12] << endl;
return 0;
}
(output is)
$ ./test1
3
311
4
411
I want to make class library, a function which its parameter is a matrix of unknown size, and the user will create his own matrix with his own size and pass it to this function to do some operations on his matrix like this, will be the function
calculateDeterminantOfTheMatrix( int matrix[][])
{
some Operations to do on matrix
}
Multi-dimensional arrays are not very well supported by the built-in components of C and C++. You can pass an N-dimension array only when you know N-1 dimensions at compile time:
calculateDeterminantOfTheMatrix( int matrix[][123])
However, the standard library supplies std::vector container, that works very well for multi-dimension arrays: in your case, passing vector<vector<int> > &matrix would be the proper way of dealing with the task in C++.
int calculateDeterminantOfTheMatrix(vector<vector<int> > &matrix) {
int res = 0;
for (int i = 0 ; i != matrix.size() ; i++)
for(int j = 0 ; j != matrix[i].size() ; j++)
res += matrix[i][j];
return res;
}
As an added bonus, you wouldn't need to pass dimensions of the matrix to the function: matrix.size() represents the first dimension, and matrix[0].size() represents the second dimension.
C solution:
In C you can't omit array size (except leftmost) when passing as function parameter.
You can write:
int a[]
but can't:
int a[][]
just for example:
int a[][20]
This constraint is here, because compiler needs to determine proper offsets for accessing array elements. However, you can make it this way:
void print_arbitrary_2D_array(void *arr, int y, int x)
{
/* cast to 2D array type */
double (*p_arr)[y][x] = (double (*)[y][x]) arr;
int i, j;
for (i = 0; i < y; ++i) {
for (j = 0; j < x; ++j)
printf(" %lf", (*p_arr)[i][j]);
putchar('\n');
}
}
double arr_1[4][3] = {
{ 3.3, 5.8, 2.3 },
{ 9.1, 3.2, 6.1 },
{ 1.2, 7.9, 9.4 },
{ 0.2, 9.5, 2.4 }
};
double arr_2[2][5] = {
{ 3.6, 1.4, 6.7, 0.1, 4.2 },
{ 8.4, 2.3, 5.9, 1.4, 8.3 }
};
print_arbitrary_2D_array(arr_1, 4, 3);
putchar('\n');
print_arbitrary_2D_array(arr_2, 2, 5);
There are multiple approaches you could take.
C way of doing things -> Pass in a int** but be extremely cautious here. This is not quite a 2D array. You will have to correctly allocate memory to this pointer, or, alternatively, you need to know the size at compile time. (For instance staticly allocating an array of size M * N and then disallowing anything bigger). In order to dynamically allocate the memory, you need to know the number of rows and columns.
C++ way -> #include <vector> after which you can simply use vector<vector<int> > &matrix (Careful about the space after the <int> unless you're using c++11 compiler.), which will allocate a vector of int vectors which is basically a 2d array. The memory management will be taken care of for you in this case.
I would write a simple class wrapper for the matrix with column and row defined.
template <typename T>
class Mat {
std::size_t _row;
std::size_t _col;
T *_mat_elem;
public:
Mat(std::size_t r, std::size_t c)
: _row(r), _col(c), _mat_elem(new T[r*c] {}
~Mat() {/* remember to do delete [] here */}
// element access, for example
T& at(std::size_t r, std::size_t c)
{
return *(_mat_elem+r*_col+c);
}
};
But actually you are re-inventing the wheels. There are good libraries for matrix handling out there.
use this method
declare an array of pointers
ex: int *a[n];
Then allocate memory for them using a for loop
ex:
for( int i=0 ; i<n ; i++ )
a[i] = new int[n];
Now pass the argument like normal array.
ex: print_array(a,n);
And print_array function looks like
print_array(int **a,int n)//the prototype for the print_array
{
//access the array using index such as
std:: cout<<a[1][1]<<endl;
}
The above case is for the array of nxn incase mxn is required then
allocate the memory like
for( int i=0 ; i<m ; i++ )
a[i] = new int[n];
then pass the both m,n and to the function and access the array in the for loop.
The Best way to use 2D array in the function that I have found so far is to use Mapping Function. As in the example below , I have use the mapping function to print 2D array
void Print2D(int x[],int ROWS,int COLS)
{
for(int i=0;i<ROWS;i++)
{
for(int j=0;j<COLS;j++)
cout << x[i*COLS+j] << ' ';
cout << endl;
}
}
Here it is how to use it in main
int main(){
int x[3][3];
Print2D(&x[0],3,3);
}
Here &x[0] is the starting address of the First Row of 2D array or more precisely Starting address of 2D array
I'm new to C/C++ and I've been cracking my head but still got no idea how to make an "structure" like this
It's supposed to be a 3D dynamic array using pointers.
I started like this, but got stuck there
int x=5,y=4,z=3;
int ***sec=new int **[x];
It would be enough to know how to make it for a static size of y and z;
Please, I'd appreciate that you help me.
Thanks in advance.
To create dynamically 3D array of integers, it's better you understand 1D and 2D array first.
1D array: You can do this very easily by
const int MAX_SIZE=128;
int *arr1D = new int[MAX_SIZE];
Here, we are creating an int-pointer which will point to a chunk of memory where integers can be stored.
2D array: You may use the solution of above 1D array to create a 2D array. First, create a pointer which should point to a memory block where only other integer pointers are held which ultimately point to actual data. Since our first pointer points to an array of pointers so this will be called as pointer-to-pointer (double pointer).
const int HEIGHT=20;
const int WIDTH=20;
int **arr2D = new int*[WIDTH]; //create an array of int pointers (int*), that will point to
//data as described in 1D array.
for(int i = 0;i < WIDTH; i++){
arr2D[i] = new int[HEIGHT];
}
3D Array: This is what you want to do. Here you may try both the scheme used in above two cases. Apply the same logic as 2D array. Diagram in question explains all. The first array will be pointer-to-pointer-to-pointer (int*** - since it points to double pointers). The solution is as below:
const int X=20;
const int Y=20;
const int z=20;
int ***arr3D = new int**[X];
for(int i =0; i<X; i++){
arr3D[i] = new int*[Y];
for(int j =0; j<Y; j++){
arr3D[i][j] = new int[Z];
for(int k = 0; k<Z;k++){
arr3D[i][j][k] = 0;
}
}
}
// one-liner
typedef std::vector<std::vector<std::vector<int> > > ThreeDimensions;
// expanded
typedef std::vector<int> OneDimension;
typedef std::vector<OneDimension> TwoDimensions;
typedef std::vector<TwoDimension> ThreeDimensions;
(this is tagged c++, after all)
EDIT in response to Joe's question
hello again Joe =) sure. here's the example:
#include <vector>
#include <iostream>
int main(int argc, char* const argv[]) {
/* one-liner */
typedef std::vector<std::vector<std::vector<int> > >ThreeDimensions;
/* expanded */
typedef std::vector<int>OneDimension;
typedef std::vector<OneDimension>TwoDimensions;
typedef std::vector<TwoDimensions>ThreeDimensions;
/*
create 3 * 10 * 25 array filled with '12'
*/
const size_t NElements1(25);
const size_t NElements2(10);
const size_t NElements3(3);
const int InitialValueForAllEntries(12);
ThreeDimensions three_dim(NElements3, TwoDimensions(NElements2, OneDimension(NElements1, InitialValueForAllEntries)));
/* the easiest way to assign a value is to use the subscript operator */
three_dim[0][0][0] = 11;
/* now read the value: */
std::cout << "It should be 11: " << three_dim[0][0][0] << "\n";
/* every other value should be 12: */
std::cout << "It should be 12: " << three_dim[0][1][0] << "\n";
/* get a reference to a 2d vector: */
TwoDimensions& two_dim(three_dim[1]);
/* assignment */
two_dim[2][4] = -1;
/* read it: */
std::cout << "It should be -1: " << two_dim[2][4] << "\n";
/* get a reference to a 1d vector: */
OneDimension& one_dim(two_dim[2]);
/* read it (this is two_dim[2][4], aka three_dim[1][2][4]): */
std::cout << "It should be -1: " << one_dim[4] << "\n";
/* you can also use at(size_t): */
std::cout << "It should be 12: " << one_dim.at(5) << "\n";
return 0;
}
You can try:
for(int i=0;i<x;i++) {
sec[i] = new int *[y];
for(int j=0;j<y;j++) {
sec[i][j] = new int [z];
}
}
And once you are done using this memory you can deallocate it as:
for(int i=0;i<x;i++) {
for(int j=0;j<y;j++) {
delete [] sec[i][j];
}
delete [] sec[i];
}
delete [] sec;
Comprehensive answers.
If you are really writing this in C++ (not rough C) I think you should take another look at this complicated data structure. IMO redesign while keeping in mind what you are trying to do would be better.
What you're trying to do is not idiomatic in C++. Of course, you can use a int***pointer for this, but this is strongly discouraged. In C++ we have better ways to get there.
vector<vector<vector<int> > > foo (5,vector<vector<int> >(4, vector<int>(3)));
This will result in something with the memory layout similar to what you asked for. It supports dynamic resizing and inner vectors to have different sizes just like in your picture. In addition, you don't have to worry about manual allocation / deletion of any of it. Also, the vectors know their size so you don't have to remember it somewhere.
But if you just want a "rectangular" 3D array where all the elements are consecutivly stored in the same memory block, you could use a boost::multiarray.
OK let us take your beginnings
int ***sec = new int**[x];
sec is now an array of int**s of length x, so now I am just going to focus on making the zeroeth element be what you want
sec[0] = new int*[y];
Now sec[0] points to array of int*s of length y, now just need to get the last bit of the tree done, so
sec[0][0] = new int[z];
And finally to get it to the form in your diagram
sec[0][0][z-1] = 0;
This does seem a little like a homework question, make sure you actually understand the answer and why it works.
If it's the actual arrays you'r having problems with look here: Declaring a pointer to multidimensional array and allocating the array
Not sure exactly what you want but you might want to read up on about linked lists.