error : no match for 'operator[]' - c++

I am solving a problem in which I m trying to pass address a 2-D array of a structure and trying to manipulate it but, whenever I use [] operator to access the array elements , I get a compile time error:
no match for 'operator[]'
in my codeblocks IDE.
#include <iostream>
using namespace std;
typedef struct mat
{
int data;
int flag;
} cell;
int mat(cell *);
int main()
{
int m,n;
cin>>m>>n;
cell game[n][m];
cout<<"The length of matrix is "<<mat(&game[0][0]);
}
int mat(cell *arr)
{
return (sizeof(arr[0])/sizeof(arr[0][0]));
}

cell game[n][m];
This is not legal C++. You are using a compiler-specific extension. At this point I advise you against using any compiler-specific extensions. Use standard C++ only. In standard C++ there are no Variable Length Arrays. Don't use arrays in your C++ programs. To get proper variable length array functionality. You should use std::vector instead, like this:
std::vector<std::vector<cell>> game;
Further,
&game[0][0]
is not an address of a 2D array. This is an address of the first element in the array. It contains no information about the number of elements. It is lost forever. You cannot pass it to some function and expect the size of the array to be recovered. To get proper array functionality with a built-in size function, use std::vector.
Last but not least,
(sizeof(arr[0])/sizeof(arr[0][0]));
arr is a cell*. arr[0] is a cell. arr[0][0] is invalid because a cell is neither an array not a pointer, nor it has a custom [] operator defined. In any case you cannot use sizeof to recover the number of elements in the array from a pointer to its first element. To get proper array functionality with a built-in size function, use std::vector.

Two things:
Your function takes a pointer to cell but since you're treating it like a 2D array, you should probably change your signature to either accept a cell ** arr or a cell arr[m][] where m is the (fixed) size of the array and must be specified. Note that these data structures have fundamentally different representations in memory - they just have the same [][] syntax for accessing elements.
You can't use the sizeof function to determine the length of an array if you pass it as a pointer to an elem. You will need to pass the dimensions along with your array, like this:
int mat(cell **arr, int m, int n);

The definition being given basically says that your class doesn't define the operator [], meaning you can't use the syntax you are trying to use.

Related

Understanding syntax of function parameter: vector<vector<int>> A[]

I'm solving a question where a function is defined as following:
vector <int> func(int a, vector<vector<int>> B[]){
// Some stuff
}
I'm confused about why the second parameter is not simply vector<vector<int>> B. Why the extra [] part in the parameter? Can someone clarify the meaning of this?
The vector, B, is populated by a similar code snippet:
vector<vector<int>> B[10];
while(num--){
cin>>u>>v>>w;
vector<int> t1,t2;
t1.push_back(v);
t1.push_back(w);
B[u].push_back(t1);
t2.push_back(u);
t2.push_back(w);
B[v].push_back(t2);
}
Just as int foo(char str[]) is a function that takes a (c-style) array of characters, so int foo(vector<vector<int>> B[]) takes an array of vectors of vectors ... of integers. This means that it's three-dimensional data, requiring 3 indices to access the elements (fundamental data type; in this case, int), like B[i][j][k] = 5. Without the extra [] in the API it'd be two-dimensional data: a vector of vectors.
Note that int foo(char str[]) is equivalent to int foo(char str[5]) which is equivalent to int foo(char * str).
In C we usually add the [] to a function declaration to imply that we expect to receive an array of those elements; while * is often used when we expect at most one element. Likewise, adding the number [5] is basically just a comment to the user of the code that they expect 5 elements, but the compiler won't enforce this. These conventions carry over to C++ when we use these c-style arrays ... which is rare.
With c-style arrays there's either going to be a maximum array size in the comments somewhere; or, more commonly, it's provided as an input. That may be what the first argument of the function is supposed to represent.
I agree with KungPhoo here that this API looks suspiciously bad. I'd expect bugs/bad performance just because the choices seem very amateurish. The c-style array means the function can't know where the end of the c-style array is - but the vectors mean that we give up some of the (niche) benefits of c-style simplicity (especially because they're nested!). It seems to be getting the worst of both worlds. But, perhaps, there may be a very niche justification for the API.
B ist a static array (C-style) of 10 elements [0 .. 9]. It's not safe and this code is a terrible mess.
Better use std::array<std::vector<str::vector<int>>, 10> B; instead to have index checking.

What is an elegant solution to this error from std::find?

I have a class which contains an array which size is unknown at compile time. The array is initialized in the constructor. Then, I have another function that checks if an element is in the array:
class myClass
{
int tab[];
public:
myClass(int array[], int length)
{
std::copy(array, array + length, tab)
}
void myFunction()
{
int x = 8;
int *ptr = std::find(std::begin(tab), std::end(tab), tdc_x);
if (ptr) /* here goes my code */
}
};
I got the following error:
error: no matching function for call to ‘begin(int [0])’
What's wrong with the above piece of code? I know that I can't use std::find with pointers, but my array is an array, not a decayed pointer.
I followed this example. I also included the algorithm header. What am I doing wrong?
I compile my code in C++11.
Edit: I get it now. But how can I do what I want to do in an elegant way?
If I use a pointer instead of the empty array, I won't be able to use std::find.
if I give my array an arbitrary size, I won't be able to copy a bigger array.
What should I do?
int tab[];
The standard doesn't allow empty arrays, but some compilers do as an extension. That doesn't make it legit tho.
If I use a pointer instead of the empty array, I won't be able to use std::find.
Not true, you can still use std::find (s is the size of your tab array).
int *ptr = std::find(tab, tab + s, tdc_x);
if I give my array an arbitrary size, I won't be able to copy a bigger array. What should I do?
Use a std::vector<int>, then call resize()

Passing a 3-dimensional variable size array by reference in C++

I've been working off of Passing a 2D array to a C++ function , as well as a few other similar articles. However, I'm running into a problem wherein the array I'm creating has two dimensions of variable size.
The initialization looks like:
int** mulePosition;
mulePosition = new int *[boardSize][boardSize][2];
The function looks like:
int moveMule (int boardSize, int ***mulePosition)
And the references look like
moveMule (boardSize, mulePosition)
Boardsize is defined at the beginning of the function, but may change per execution.
The array, properly sized, would be int [boardSize][boardSize][2].
Either use a plain '3-dimensional' array via
int* mulePosition = new int[boardsize*boardsize*2];
and address its elements calculating the offset from the beginning: mulePosition[a][b][c] is mulePosition[boardSize*2*a + 2*b + c],
or use array of arrays of arrays (which would correspond to your int*** declaration) or better (and simpler) vector of vectors of vectors, although the initialization would be a little more complex (you would need to initialize every array/vector).
Either use a std::vector<std::vector<int>> if boardSize is not a const or std::array<std::array<boardSize>, boardSize> (see Multidimensional std::array for how to initialize the std::array).
That being said, it looks like a good idea to hide this in a class Board which provides a nice interface.

How to point to an array of arrays in C++?

I have a 4D array and i would like to create a function that i could use to refer to a 2D array inside the 4D array and read its data by appending square braces with indexes to the function call.
int numbers[2][3][4][4] = {
{
{{1,2,3,4}, {4,3,2,1}, {6,7,8,9}, {9,8,7,6}},
{{0,1,0,1}, {1,0,1,0}, {1,1,0,0}, {0,0,1,1}},
{{5,4,1,8}, {4,2,5,1}, {7,2,5,8}, {4,2,5,1}}
},
{ /* same stuff */ }
};
If i wanted to access just {4,2,5,1} for example, i could create a function that returns a pointer to the first int of that array (&number[0][2][1][0]), and access the elements with func()[1], func()[2], func()[3], well... you know that.
int* func() {
return &numbers[0][2][1][0];
}
// func()[2] => 5
But how could i create a function that returns a reference to numbers[0][2], so for example i could do func()[1][0] and it would return 5?
It seems i should work up my understanding of C/C++ pointers, references and arrays, but i will also appreciate "std" and C++11-specific solutions (using some cool std::class over standard arrays). Thanks :)
In C++ the best approach would be to return a reference to a 2D array
int (&func())[4][4] {
return numbers[0][2];
}
Now you can access it as
func()[i][j]
This fully preserves the 2D array type and keeps the natural access syntax.
If you insist on returning a pointer specifically, then you can return a pointer to the first 1D array in that 2D array
int (*func())[4] {
return numbers[0][2];
}
which will preserve the access syntax as
func()[i][j]
but, as you can see, the price of this is decay of 2D array type to 1D array type.
Or, as has already been suggested, you can return a pointer to a 2D array
int (*func())[4][4] {
return &numbers[0][2];
}
but in this case you will have to remember to access that 2D array elements as
(*func())[i][j]
i.e. it preserves the 2D array type, but forces you to use a more convoluted access syntax.
For this reason reference seems to be the best approach (as long as you insist on working with raw arrays), combining the "best" features of both pointer-based approaches.
P.S. Typedefing the 2D array type will produce much more readable function declarations. E.g. if you do
typedef int Numbers2D[4][4];
then the first variant will turn into
Numbers2D &func() {
return numbers[0][2];
}

Declaring char[][512]?

I have an C++ SDK that requires a char[][512] as a parameter. I know that this is supposed to be a list of file names and the number of files could vary. For the life of me I cannot figure out how to declare this. I have an array of CStrings and I am trying to copy them over using strcpy_s and then pass them into the SDK. Any idea on how to do this?
This declaration has a special meaning when used to declare parameter of a function. Within the parameter list it is equivalent to char[100][512], char[123][512], char[3][512] (you get the idea - the first size can be just anything, it is simply ignored) and also to char (*)[512]. Effectively, it will accept as an argument a 2D array of chars with flexible (arbitrary) first size.
The array that you will actually pass to this function should be declared with a concrete first size, for example
char names[3][512] = { "abc", "cde", "fgh" };
if you know the first size at compile time, of course.
If the first size is only known at run time (say, n), you'll have to allocate the array dynamically
char (*names)[512] = new char[n][512];
// Now fill it with names
or, more elegantly, with a typedef
typedef char TName[512];
TName* names = new TName[n];
// Now fill it with names
I expect that the SDK function you are talking about also asks you to pass the first size of the name array as another parameter.
It means 2D array of char. The number of rows could vary, and it should/may be specified in another parameter. C/C++ compilers need to know the number columns when a 2D arrays is passed ,So they can build the mapping function. Simply because arrays decay to pointers when they are passed as parameters, size information is lost. For example:
void fun(char matrix[][512], int rows);
...
char matrix[100][512];
...
fun(matrix, 100);
The mapping function that the compiler construct for a 2D array is similar to:
// arrays in C/C++ are stored in Row-Major Order
matrix[i][j] == matrix[i*numberOfColumns + j]
As you can see, when a 2D array is passed and the size information is lost, we need only the number of columns to index any element in this array.
Here is a way to convert an argv-style array of filenames into the form your SDK needs.
typedef char Char512[512];
Char512 * convert(const char *names[], int n)
{
Char512 * arr;
arr = new char[n][512];
for (int i = 0; i < n; n++)
::strncpy(arr[i], names[i], 512);
return arr;
}
When in doubt, use a typedef.
Just a reminder, if you new[] something, you must delete[] (not delete) it sometime.