C++ function calling to 2d array [duplicate] - c++

This question already has answers here:
Passing a 2D array to a C++ function
(18 answers)
Closed 7 years ago.
I have in class County.h constructor:
struct Country {
Country(double**, int);
};
and in main I have graph[Size][Size] and I want to call the constructor for County.
int main() {
double graph[Size][Size];
Country c(graph, 0);
}
But its giving me error no matching function for call to ‘County::County(double [22][22], int)’
What I can do in order to solve this problem?

double [Size][Size] and double** are not at all the same type. That is what your compiler doesn't like.
Change your constructor prototype or the way you declare your array. But you cannot directly cast an array of array to a pointer of pointer.
struct Country {
Country(double[Size][Size], int);
};
OR:
int main() {
double** graph = new (double*)[Size];
for (int i = 0; i < Size; ++i) {
graph[i] = new double[Size];
}
Country c(graph, 0);
// Don't forget to delete your graph then.
}
Note that the first one requires that you would know the size before your code start its execution (storing Size in a macro for instance), but the second one is longer to code, and you will have to manipulate more RAM memory, that can lead to mistakes if you are not careful.

An alternative is to declare your constructor as a template and pass the array by (const) reference,
struct Country {
template<size_t N>
Country(double /*const*/ (&arr)[N][N], int);
};
In this way, the template will deduce the size of the array directly. Of course, the downside is that the above won't work with double pointers. The upside is that the compiler will strongly check the type and your program won't even compile if the array is not made of doubles (no conversions are being performed at type deduction) or if it is not square.

Related

Passing a pointer to an int array to a member function, error: invalid types 'int[int]' for array subscript

Ok, I'm fairly new to programming, and c++ so please take it easy on me. I am trying to write a program that takes in the dimensions of a metal plate for a 2-D finite element method analysis (thickness neglected). So, I created a class for my part (the plate), the elements for the mesh, and the nodes for the elements. The mesh will consist of square elements and will be applied over the front face of the plate. Right now, I'm working on getting the mesh sorted out before I move on to the element and node classes.
I'm using (or wanting to use) dynamic allocation to create a 2-D array (my mesh) containing the elements of the mesh. I'm trying to write a function, "meshingPart", to create the 2-D array with the number of rows being the height of the plate, and the columns being the length of the plate.
When I run the program, I get these errors and I'm not sure how to fix them:
In member function 'void PartClass::meshingPart(int&, int, int)':
error: invalid types 'int[int]' for array subscript
At global scope:
error: expected constructor, destructor, or type conversion before '(' token
Also, when I use my printPart() function, will it print the pointer's address, or the values of the array? I'm not completely sure about this, I'm also new to pointers.
Any help would be much appreciated! Thanks in advance.
class PartClass
{
private:
const int HEIGHT; // mm
const int LENGTH; // mm
const int WIDTH; // mm
const int SEED; // mm
const int MESHROW;
const int MESHCOL;
int *partMesh; // Mesh array - an int pointer
// Creates the mesh for the part by generating elements to fill the width and length
// of the part. The elements are stored in a 2-D array.
void meshingPart(const int &partMesh, int inRow, int inCol);
public:
// Constructs a part with the given parameters, seeds the part for the mesh,
// then creates the mesh by generating square elements with length = height = SEED.
PartClass(int inHeight, int inLength, int inWidth, int inSeed);
void printPart()
{
cout << "Part mesh:" << *partMesh << endl;
}
};
class ElementClass
{
private:
int elemID;
static int numElems;
// Shape functions:
int N1;
int N2;
int N3;
int N4;
public:
// Default constructor
ElementClass()
{
elemID = numElems;
numElems++;
};
};
PartClass :: PartClass(inHeight, inLength, inWidth, inSeed)
{
HEIGHT = inHeight;
LENGTH = inLength;
WIDTH = inWidth;
SEED = inSeed;
MESHROW = HEIGHT/SEED;
MESHCOL = LENGTH/SEED;
// Dynamically declares an array, gets memory, assigns address to partMesh.
partMesh = new int[MESHROW][MESHCOL];
meshingPart(&partMesh, MESHROW, MESHCOL);
}
void PartClass :: meshingPart(int &partMesh, int inRow, int inCol)
{
for( int i; i < inRow; i++)
{
for( int j; j < inCol; j++)
{
partMesh[i][j] = ElementClass();
}
}
}
There are multiple problems with the shown code, not a single problem. All of the problems must be fixed in order to resolve all compilation errors.
void PartClass :: meshingPart(int &partMesh, int inRow, int inCol)
The first parameter to this class method is declared as a reference to a single, lonely int. It is not an array, hence the code in this class method that treats it as an array will make your C++ compiler very, very sad.
int *partMesh; //
partMesh = new int[MESHROW][MESHCOL];
partMesh is declared as a pointer to an int. The new expression produces, effectively, a pointer to an array of MESHCOL ints. In C++ you cannot convert a pointer to an array into a different kind of a pointer.
Furthermore, nothing shown here requires the use of new in the first place. partMesh could simply be a std::vector<vector<int>>, and the new replaced by a strategic resize(). As an extra bonus your C++ program will automatically delete all this memory when it is no longer needed, not leak it, and also implement correct copy/move semantics where needed!
meshingPart(&partMesh, MESHROW, MESHCOL);
As we've concluded, the first parameter to the function is a reference to an array. Passing to it an address of a pointer to int will also not work.
Furthermore, since partMesh is a member of the same class, having one function in the class pass, in some form, a member of the same class to another class method accomplishes absolutely useful, whatsoever. Since it's a member of the same class it doesn't need passing, the class method can access it directly. This is what, after all, classes are all about.
In conclusion:
There are several problems regarding the C++ type system that are causing these compilation errors.
It is not necessary to even use new here, to initialize the pointer, and either its type needs to be adjusted to reflect that it's a pointer to a 2D array, or the new statement itself needs to be adjusted to allocate a one-dimensional array, since that's the only thing C++ allows you to convert to a plain pointer. And even that is overnegineered, since a std::vector will take care of all these pesky details by itself.
It is not necessary to even pass the member of the same class to the same class's method, as a parameter, just have the class method access it directly.
It's apparent that the likely process that produced the shown code was to write it in its entirety, and only try to compile after the whole thing was written. An avalanche of compilation errors is almost guaranteed any time this approach is used. It is far more productive to write a large program by writing only a few lines at a time, testing them, make sure they work correctly, and only then write a few more. This way, the number of errors that need to be fixed will remain quite small, and manageable.

local array length is different from when it is called from a function

In the following code, std::extent<decltype(columns)>::value calculates the length of the given array. However, when the array is a function argument, the compiler behaves in different way. Could some one help me how to fix it?
output:
local array length: 5
function array length: 0
code:
#include <iostream>
#include <string>
void showcolumns_num(std::string columns[])
{
int columns_num=std::extent<decltype(columns)>::value;
std::cout<<"function array length: "<<columns_num<<std::endl;
}
int main()
{
std::string column_list[]={"col1","col2","col3","col4","col5"};
// local calculation of column number
int columns_num=std::extent<decltype(column_list)>::value;
std::cout<<"local array length: "<<columns_num<<std::endl;
// function calculation of column number
showcolumns_num(column_list);
return 0;
}
You have to pass array by reference to avoid the decay to pointer which so loses size information:
template <std::size_t N>
void showcolumns_num(std::string (&columns)[N])
Live example.
That because of the declaration:
void showcolumns_num(std::string columns[])
is the same as:
void showcolumns_num(std::string * columns)
But declaration:
std::string column_list[]={"col1","col2","col3","col4","col5"};
is the same as:
std::string column_list[5]={"col1","col2","col3","col4","col5"};
So compiler doesn't know about array size inside the function.
Just use the std::vector< std::string >.
The short answer is: Don't use arrays. Instead of string columns[N];, use vector<string> columns; or vector<string> columns(N,"");. In this answer, I'll talk a bit more about arrays, they are "interesting". But arrays are "interesting" in the way that cancer is interesting, somebody has to understand cancer, but we want to get rid of it and most people don't want to be experts.
C arrays are really weird things. They can't be passed by value, but they can be passed by reference, and C++ makes it quite easy. If you are determined - as an intellectual exercise - to pass arrays, then you can use this:
template<size_t N>
void showcolumns_num(std::string (&columns)[N])
Non-array types, like int, or struct Person, or list<vector<string>>, can be passed by value or by reference. But arrays cannot be passed by value.
If you attempt to pass an array by value, the compiler will do a trick where it will instead pass a pointer to the first element of the array. This is called pointer decay.
This means that, without warning, the compiler will rewrite your function declarations
void showcolumns_num(std::string columns[]) { // this is what you write
// changed to
void showcolumns_num(std::string* columns) { // ... but this is what you get
and every call to showcolumns_num will be changed from:
showcolumns_num(column_list); // this is what you write
// changed to
showcolumns_num(&(column_list[0])); // ... but this is what you get
The reason behind this is historical, and is related to an earlier language called B.
Variables are declared as local variables, or as global variables, or as function parameters. For local and global variables, the compiler will generally respect your wishes, but not for function parameters:
void foo(int x[5]) { // silently converted to int *x
int y[10]; // y really will be an array
}

Returning an array ... rather a reference or pointer to an array

I am a bit confused. There are two ways to return an array from a method. The first suggests the following:
typedef int arrT[10];
arrT *func(int i);
However, how do I capture the return which is an int (*)[]?
Another way is through a reference or pointer:
int (*func(int i)[10];
or
int (&func(int i)[10];
The return types are either int (*)[] or int (&)[].
The trouble I am having is how I can assign a variable to accept the point and I continue to get errors such as:
can't convert int* to int (*)[]
Any idea what I am doing wrong or what is lacking in my knowledge?
If you want to return an array by value, put it in a structure.
The Standard committee already did that, and thus you can use std::array<int,10>.
std::array<int,10> func(int i);
std::array<int,10> x = func(77);
This makes it very straightforward to return by reference also:
std::array<int,10>& func2(int i);
std::array<int,10>& y = func2(5);
First, the information you give is incorrect.
You write,
“There are two ways to return an array from a method”
and then you give as examples of the ways
typedef int arrT[10];
arrT *func(int i);
and
int (*func(int i))[10];
(I’ve added the missing right parenthesis), where you say that this latter way, in contrast to the first, is an example of
“through a reference or pointer”
Well, these two declarations mean exactly the same, to wit:
typedef int A[10];
A* fp1( int i ) { return 0; }
int (*fp2( int i ))[10] { return 0; }
int main()
{
int (*p1)[10] = fp1( 100 );
int (*p2)[10] = fp2( 200 );
}
In both cases a pointer to the array is returned, and this pointer is typed as "pointer to array". Dereferencing that pointer yields the array itself, which decays to a pointer to itself again, but now typed as "pointer to item". It’s a pointer to the first item of the array. At the machine code level these two pointers are, in practice, exactly the same. Coming from a Pascal background that confused me for a long time, but the upshot is, since it’s generally impractical to carry the array size along in the type (which precludes dealing with arrays of different runtime sizes), most array handling code deals with the pointer-to-first-item instead of the pointer-to-the-whole-array.
I.e., normally such a low level C language like function would be declared as just
int* func()
return a pointer to the first item of an array of size established at run time.
Now, if you want to return an array by value then you have two choices:
Returning a fixed size array by value: put it in a struct.
The standard already provides a templated class that does this, std::array.
Returning a variable size array by value: use a class that deals with copying.
The standard already provides a templated class that does this, std::vector.
For example,
#include <vector>
using namespace std;
vector<int> foo() { return vector<int>( 10 ); }
int main()
{
vector<int> const v = foo();
// ...
}
This is the most general. Using std::array is more of an optimization for special cases. As a beginner, keep in mind Donald Knuth’s advice: “Premature optimization is the root of all evil.” I.e., just use std::vector unless there is a really really good reason to use std::array.
using arrT10 = int[10]; // Or you can use typedef if you want
arrT10 * func(int i)
{
arrT10 a10;
return &a10;
// int a[10];
// return a; // ERROR: can't convert int* to int (*)[]
}
This will give you a warning because func returns an address of a local variable so we should NEVER code like this but I'm sure this code can help you.

c++ pass auto matrix to function [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I use arrays in C++?
i have a problem.
i have to use auto darray(matrix).
const int size_m=10;
const int size_n=10;
void process(int *x)
{
//i can pass array, all is well, i work as with dynamic allocated array
for(int i=0;i<size_m;scanf("%d",&x[i]),i++);
}
void input_m(int **x)
/*
mistake is here,
a cause of my problem that i'm trying to work with matrix allocated in stack(auto matrix,local) as with dynamically allocated matrix.
i receive error like this : "cannot convert ‘int [100][100]’ to ‘int**’ in assignment" how should i pass it?
*/
{
for(int i=0;i<size_m;i++)
for(int j=0;j<size_n;j++)
scanf("%d",&x[i][j]);
}
int main()
{
int x[size_m];
input(x);
int matr_x[size_m][size_n];
input_m(matr_x);
return 0;
}
THANK YOU! it works.. it was so simple, as usual)
const int sizem=3;
const int sizen=3;
void _input(int x[sizem][sizen])
{
for(int i=0;i<sizem;i++)
for(int j=0;j<sizen;x[i][j]=1,j++);
}
int main()
{
int m=10,n=10;
int x[sizem][sizen]={{1,2,3},{5,7,4}};
_input(x);
for(int i=0;i<sizem;i++)
{ for(int j=0;j<sizen;printf(" %d",x[i][j]),j++);
puts("");
}
puts("");
return 0;
}
Your two-dimensional array is incompatible with the function you wrote for fundamental reasons of how memory works in C.
When you write int matrix[size_m][size_n] you are telling the compiler that you want a block of sizeof(int)*size_m*size_n bytes and you intend to store integers in it.
When you write int ** x you are telling the compiler that x is a pointer to a pointer to an integer. If you want to use x as a two-dimensional array, then x should point to not just one pointer, but the first pointer in an array of pointers, i.e. a contiguous region of memory that contains pointers for each row of your matrix. But you don't have any such array of pointers anywhere in the program you posted.
Since you know the dimensions of your matrix at compile time, you can fix this by changing the type of x be int x[size_m][size_n]. Better yet, make a typedef:
typedef int MyMatrix[size_m][size_n];
void input_m(MyMatrix x){ ... }
int main()
{
MyMatrix matr_x;
...
}
First of all, see the answer to this question. Your code should compile if you change void input_m(int **x) to void input_m(int x[size_m][size_n]) (assuming that both size_m and size_n are constants). Note that, as stated in the question that I linked to, "in general, to pass 2D arrays to functions you need to specify the array dimensions for all but the first dimension."

Dealing with array size

I happened to ask myself a question about arrays in c++.
Well, we all know that arrays are fixed collections of something, I say fixed because it is necessary to declare array length when defining arrays.
Well, let's consider an example:
char myarray[10] = {'\0'};
int sz = sizeof(myarray); // It is supposed to be 10
Well, it is correct, 10 is the number returned by sizeof. This can be done by the compiler because he knows how much space it placed for that variable.
Now consider what happens in this situation:
void dosome(mystruct* arr) {
int elements = sizeof(arr)/sizeof(mystruct);
for (int i = 0; i < elements; i++) {
// Do something hoping no overflow will ever occur
}
}
Nice... but I suppose it can be overflow prone. If I pass to this function an array I created in a "normal" way, everything should be fine:
mystruct array[20];
dosome(array);
No problem. But if I do this:
mystruct* array = (mystruct*)malloc(80*sizeof(mystruct));
dosome(array);
WHAT HAPPENS???????????????????
I would like to understand how sizeof behaves, this function is evaluated at compile time right??? ok, what happens when I use not an array, but something very cumbersome like a block of data like that one? furthermore, I could realloc it woth another call to malloc and ask to dosome to process that datablock again. Will it work?
I could try it physically, but I would get some exact answer about the behavioir of sizeof.
Thank you.
it's wrong starting from the mystruct array[20] example. Because the function receives a pointer type, and not an array type, it cannot deduce the number of elements in the array. you are actually getting the size of a mystruct* when you perform sizeof(arr).
You can use templates to write functions which take arrays as parameters, but the suggested way in C++ is to use vectors, if I am not wrong.
The "way" to receive arrays as parameters would be to write something like:
template <int N> void somefunction(int (&v)[N]);
EDIT corrected the function declaration. oops.
void dosome(mystruct* arr) {
int elements = sizeof(arr)/sizeof(mystruct);
for (int i = 0; i < elements; i++) {
// Do something hoping no overflow will ever occur
}
}
What type does arr have in this example? mystruct*! And it's size is most likely 4 or 8. If you want to pass statically/automatically allocated arrays (not new'd) to functions preserving the size so that your trick works, pass by REFERENCE!
template <int N>
void dosome(mystruct (& arr) [N]) {
for (int i = 0; i < N; i++) {
// Do something . No overflow will occur
}
}
Also note this
int a[20];
sizof a; //equals to 20*sizeof(int)
int* b = new int [20];
sizeof b; //equals to sizeof pointer, most likely 4
sizeof is a compile-time operator. And here it computes only the size of a pointer.