How am I supposed to pass static 2d array to function in cpp as an argument? I tried something like that:
void foo(int (&tab)[N][N]) {
// function body
}
int main() {
int n;
cin >> n;
int tab[n][n];
foo(tab); // doesn't work
return 0;
}
I get "no matching function error" when I try to call foo.
I need static arrays, because vectors are too slow for my needs. I would like to avoid declaring array with 10000 rows and columns, too. Moreover, I would want to use functions, because it will make my code readable. Is there any solution for this problem which will meet my expectations?
With cin >> n;int tab[n][n];, you declare a variable length array (i.e. an array which's dimensions are not compile-time-constants).
You have two problems here: First, they are not supported by standard C++, and second they are not compatible with fixed size array parameters you introduced.
If you declare your array with compile time known size, however, it will work:
#define N 10
void foo(int (&tab)[N][N]) {
cout << tab[1][1] << endl;
}
int main() {
int tab[N][N] = {};
tab[1][1]=15;
foo(tab);
return 0;
}
The classical C++ solution would involve using vectors of vectors. If it's not suitable (because you want more speed or more control over memory), you can define your own class for a square 2-D array.
One idea I used in my code is, implement it using an underlying 1-D vector, with accessor method returning a pointer.
struct My_2D_Array
{
explicit My_2D_Array(size_t n):
m_size(n),
m_data(n * n)
{
}
int* operator[](size_t i)
{
return m_data.data() + i * m_size;
}
size_t m_size;
std::vector<int> m_data;
};
This not only lacks all sanity checks, and also makes bound-checked access impossible (because the accessor returns a bare pointer), but will work as a quick-and-dirty solution.
Usage in your code:
int foo(My_2D_Array& matrix)
{
// example
return matrix[2][3] + matrix[3][2];
}
int main()
{
int n;
cin >> n;
My_2D_Array tab(n);
foo(tab);
return 0;
}
This idea is highly customizable - you can make the code for My_2D_Array as simple or as clever as you want. For example, if you still don't like usage of vector, even though it's 1-D, you can manage (allocate/deallocate) your memory separately, and store int*, instead of vector<int>, in My_2D_Array.
Just use a vector<> of vector<int>. No need for mucking around with non-standard arrays.
Related
(I'm a student and this is my first time posting so go easy on me.)
I want to create a function that takes a 2D array as an argument and in that array, I'd like to have a variable that I want to modify later in the code. This is the closest thing to an example of what I want:
int size; //the variable I want to change later
void function(int[][size]);
int main(){
cin >> size;
int array[size][size]; //the array I'm using with the variable as a parameter
function(array)
}
void function(int array[][size]){
//Do thing....
}
The code above does give me an error (array bound is not an integer constant) so if I make the variable a constant it will compile as seen here:
const int size = 10;
void function(int[][size]);
int main(){
int array[size][size];
function(array)
}
void function(int array[][size]){
//Do thing....
}
This does compile like I said, but now I can't modify the variable and need to declare its value in the code beforehand. I assume that the variable needs to be global so that I can use it in the function, and with that said, I can't get pointers to work either most likely because it's a global variable and not a local one. Here's an example of something I tried, but got an error (invalid conversion from ‘const int*’ to ‘int*’):
const int size = 10;
void function(int[][size]);
int main(){
int *other = &size;
*other = 5;
}
Any help would be appreciated, thanks.
Plain ol' arrays aren't resizeable in C++. Even more frustrating, their size has to be a constant - you can't make the size a variable that gets set at runtime. Ever more frustrating, the size you put in an array that's a function parameter is a constraint, and it's not even enforced. It's just decor.
As it was hinted in the comments, std::vector<TYPE> is the go-to "resizeable array" in C++. You can create a vector like this:
#include <vector>
int main() {
std::vector<int> my_int_array;
}
And you can resize it like this:
int new_size = 42;
my_int_array.resize(new_size);
And you can pass it to a function by reference(see the &) so that changes to myint_array inside the function affect it outside the function.
void my_awesome_function(std::vector<int>& int_array);
my_awesome_function(my_int_array);
So let's say you have a 2D matrix, implemented as a vector of vectors:
std::vector<std::vector<int>> matrix = { { 1,2,3 }, { 4,5,6 } }
If you want to change the number of columns, you have to resize each row array:
int new_column_count = 10;
for (auto& row : matrix) {
row.resize(new_column_count );
}
You can pass around matrix by reference (e.g. std::vector<std::vector<int>>&) and resize it when you need to.
I have written the following code but it is showing the error
use of parameter outside function body before ‘]’ token
The code is
#include <iostream>
using namespace std;
int n=10;
void a(int s[n][n])
{
cout<<"1";
}
int main()
{
int s[n][n]={0};
a(s);
}
I am trying to pass a multidimensional array of variable size using global variable. I don't want to use vectors in this.
Firstly C++ doesn't have variable-length arrays, So Instead of int s[n][n]={0}; you should use
std::vector<std::vector<int>> s(10,std::vector<int>(10));
Secondly how to pas 2D array to a function,
void a(std::vector<int> **s,int rows, int cols){
cout<<"1";
/* stuff with 2D array */
}
You've already received answers which explain the why. I'm offering this only as a matter of completeness to C++. Personally, though I don't understand why you're avoiding vectors, they do offer a more intuitive or pleasing solution. Inside of your function for handling the vectors, you can always consult std::vector<>.size() to ensure you stay within bounds or std::vector<>.at() and catch the exception that is thrown when accessing out of bounds. Nevertheless, your particular question may also be solved by templates. Below is your code, slightly modified, with comments to illustrate. I tested using gcc 4.8.5:
#include <iostream>
using namespace std;
// Made constant so that the compiler will not complain
// that a non-constant value, at compile time, is being
// used to specify array size.
const int n=10;
// Function template. Please note, however, this template
// will only auto-gen functions for 2D arrays.
template<int lb>
void a(int s[][lb])
{
// output the last element to know we're doing this correctly
// also note that the use of 9 hard-codes this function template
// to 2D arrays where the first dimension is always, at least, 10
// elements long!!!!!!
cout << s[9][lb - 1] << endl;
}
int main()
{
int s[n][1];
s[9][0] = 15;
a<1>(s); // explicitly call template with the size of the last dimension
a(s); // Call the same function generated from the previous call
int t[n][2];
t[9][1] = 17;
a(t); // compiler implicitly determines the type of function to generate
}
You can't. Your function a() needs to know the last dimension, which is the length of each row in the matrix. You need to pass this as an extra parameter to your function.
void a(int * matrix, int rows, int columns) {
int row = ...
int column = ...
if (row < rows && column < columns) {
cout << matrix[row*columns + column];
}
}
int main() {
...
a(&s[0][0], 10);
...
In my platformer game which I'm writing in Visual C++, each level will initially be stored as a 2-dimensional array of ints. I decided it would make more sense to store this array in a class, so I created a class called Level. It looks like this:
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
map = a;
}
int getcell(int row, int column) {
return map[row][column];
}
};
As far as I can see - from looking up tutorials on class constructors, and passing 2-dimensional arrays as parameters, this should work, so I really don't understand why it doesn't.
On the line where I do map = a, I get an error: Error: expression must be a modifiable lvalue. I've looked this error up on stackoverflow, but I can't find any answers which relate to my problem.
So, how can I fix this error?
This doesn't really have anything to do with a constructor. You cannot assign arrays in C++. Whether in the constructor, or anywhere else.
There are two ways to work around it. The first way is the brute force way. Instead of
map = a;
write a loop to copy the contents of the array from the constructor's parameter into the class member array.
The second way is to stuff the array into an intermediate class:
class Level {
public:
struct level_map {
int map[20][30];
};
private:
level_map map;
public:
Level(const level_map &initial_map) : map(initial_map)
{
}
int getcell(int row, int column) {
return level_map.map[row][column];
}
};
This may or may not be practical, and introduces a little bit more complexity.
But the real answer here is to use std::vectors instead of plain arrays, which will solve all of these problems.
Others have already mentioned the real reason: you cannot assign an array to another using = operator. My two cents about your class:
map is not a good name, it may get conflict with std::map if using namespace std; or using std::map was specified somewhere.
The constant array sizes make this class non-reusable. Class should be flexible to allow any N*M sized 2D array. For this, better to use vector<vector<int>>.
getcell should be a const method, and it should do error checking with row and column numbers passed.
If you want this class to have static-sized array sizes and compile time, you may use class templates with row and column sizes as non type template arguments.
template<size_t row, size_t column>
class Level
{
int _map[row][column];
public:
Level(int src[row][column])
{
memcpy(_map, src, sizeof(_map)); // why not simply 'memcpy' ?
}
};
int main()
{
int source[10][2] = { {1, 2}, {3,4} };
Level<10, 2> ten_by_2(source);
}
Here the map is a constant value, which could not been assigned as an lvalue. This could be fixed by iterating the element of the array, and assign a[i][j] to map[i][j].
class Level {
private:
int map[20][30];
public:
Level(int a[20][30]) {
for(int i = 0; i < 20; ++i)
for(int j = 0; j < 30; ++j)
map[i][j] = a[i][j];
}
int getcell(int row, int column) {
return map[row][column];
}
};
I am trying to return an array Data Member from one smaller 2D Array Object, and trying to insert the array into a larger 2D array object. But when attempting this, I came into two problems.
First problem is that I want to return the name of the 2D array, but I do not know how to properly syntax to return 2D Array name.
This is what my 2D Array data member looks like
private:
int pieceArray[4][4];
// 2D Smaller Array
and I want to return this array into a function, but this one causes a compiler error:
int Piece::returnPiece()
{
return pieceArray; //not vaild
// return the 2D array name
}
I tired using this return type and it worked:
int Piece::returnPiece()
{
return pieceArray[4][4];
}
But I am unsure if this is what I want, as I want to return the array and all of it's content.
The other problem is the InsertArray() function, where I would put the returnPiece() function in the InsertArray()'s argument.
The problem with the InsertArray() is the argument, heres the code for it:
void Grid::InsertArray( int arr[4][4] ) //Compiler accepts, but does not work
{
for(int i = 0; i < x_ROWS ; ++i)
{
for (int j = 0; j < y_COLUMNS ; ++j)
{
squares[i][j] = arr[i][j];
}
}
}
The problem with this is that it does not accept my returnPiece(), and if i remove the "[4][4]", my compiler does not accept.
Mostly all these are syntax errors, but how do I solve these problems?
Returning the whole pieceArray in returnPiece()
The correct syntax for the argument in InsertArray()
The argument of InsertArray() accepting the returnPiece()
These 3 are the major problems that I need help with, and had the same problem when I attempt to use the pointer pointer method. Does anyone know how to solve these 3 problems?
When passing your array around, you have to decide whether or not you want to make a copy of the array, or if you just want to return a pointer to the array. For returning arrays, you can't (easily) return a copy - you can only return a pointer (or reference in C++). For example:
// Piece::returnPiece is a function taking no arguments and returning a pointer to a
// 4x4 array of integers
int (*Piece::returnPiece(void))[4][4]
{
// return pointer to the array
return &pieceArray;
}
To use it, call it like so:
int (*arrayPtr)[4][4] = myPiece->returnPiece();
int cell = (*arrayPtr)[i][j]; // cell now stores the contents of the (i,j)th element
Note the similarity between the type declaration and using it - the parentheses, dereferencing operator *, and brackets are in the same places.
Your declaration for Grid::InsertArray is correct - it takes one argument, which is a 4x4 array of integers. This is call-by-value: whenever you call it, you make a copy of your 4x4 array, so any modification you make are not reflected in the array passed in. If you instead wanted to use call-by-reference, you could pass a pointer to an array instead:
// InsertArray takes one argument which is a pointer to a 4x4 array of integers
void Grid::InsertArray(int (*arr)[4][4])
{
for(int i = 0; i < x_ROWS; i++)
{
for(int j = 0; j < y_COLUMNS ; j++)
squares[i][j] = (*arr)[i][j];
}
}
These type declarations with pointers to multidimensional arrays can get really confusing fast. I recommend making a typedef for it like so:
// Declare IntArray4x4Ptr to be a pointer to a 4x4 array of ints
typedef int (*IntArray4x4Ptr)[4][4];
Then you can declare your functions much more readable:
IntArray4x4Ptr Piece::returnPiece(void) { ... }
void Grid::InsertArray(IntArray4x4Ptr arr) { ... }
You can also use the cdecl program to help decipher complicated C/C++ types.
It seems like you need to read up more on pointers in C++ and on pass by reference vs. pass by value.
Your returnPiece method is defined as returning the value of a single cell. Given the index (e.g., [4][4]) you return a copy of the contents of that cell, so you won't be able to change it, or more correctly, changing it would change the copy.
I'm sure someone will give you the correct syntax, but I would really recommend learning this stuff since otherwise you may use the code that you do get incorrectly.
Here is how I would do it:
class Array {
public:
Array() {
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
(*this)(i, j) = 0;
}
}
}
int &operator()(int i, int j)
{
return pieceArray[i][j];
}
private:
int pieceArray[4][4];
};
You can then do something like:
Array x; // create 4x4 array
x(1, 2) = 3; // modify element
Trouble with Adam Rosenfield's arrayPtr in that Piece::pieceArray can change out from under you. (Copy-by-reference vs Copy-by-value.)
Copy-by-value is inefficient. But if you really want to do it, just cheat:
struct FOO { int piece [4][4]; };
FOO Piece::returnPiece()
{
FOO f;
memcpy( f.piece, pieceArray, sizeof(pieceArray) );
return f;
}
void Grid::InsertArray( const FOO & theFoo )
{
// use theFoo.piece[i][j]
}
Of course, a better, more Object-Oriented solution, would be to have returnPiece() create and return a Piece or Array object. (As Juan suggested...)
I have got a small problem with 1D array in c++. I have got a function line this:
void func(int (&array)[???])
{
// some math here;
"for" loop {
array[i] = something;
}
}
I call the functions somewhere in the code, and before I made math I'm not able to know dimension of the array. The array goes to the function as a reference!, because I need it in the main() function. How I can allocate array like this?, so array with ?? dimension goes to the function as reference then I have to put the dimension and write to it some values.
Since you're using C++, why not use a std::vector<> instead?
Other have mentioned that you should use std::vector in C++ and they are right.
But you can make your code work by making func a function template.
template <typename T, size_t N>
void func(T (&array)[N])
{
// some math here;
"for" loop {
array[i] = something;
}
}
Use a pointer, not a reference:
void func(int *a, int N);
Or, easier, use a vector:
void func(std::vector<int> &a);
Vectors can be allocated by simply saying
std::vector<int> a(10);
The number of elements can be retrieved using a.size().
If the array you pass to func is a stack array, and not a pointer, you can retain its size by using a function template:
template <class T, size_t N>
void func(T(&array)[N])
{
size_t array_length = N; // or just use N directly
}
int main()
{
int array[4];
func(array);
}
That said, as others have already pointed out, std::vector is probably the best solution here.
As well as vector which has been suggested you could possibly use valarray which is also part of STL and is intended specificially to handle mathematical collections.
What you have to realize, is that arrays are pointers. A definition like int array[5] will allocate space for 5 integers on the stack and array will be the address of the first value. Thus, to access the first value in the array, you can write
array[0] or *array (which is the same as *(array + 0))
In the same way to retrieve the address of the third element, you can write
&array[2] or array + 2
Since arrays are pointers, you don't have to worry about the runtime size of your array if you would like to pass it to a function, simply pass it as a pointer:
void func(int *array)
{
int size;
//compute size of the array
for (int i = 0; i < size; ++i)
{
//do whatever you want with array[i]
}
}