Passing 2-D array as argument - c++

I am trying to pass a 2-d array to a function which accept a pointer to pointer. And I have learnt that a 2-d array is nothing a pointer to pointer(pointer to 1-D array). I when I compile the below code I got this error.
#include<iostream>
void myFuntion(int **array)
{
}
int main()
{
int array[][]= {{1,2,3,4},{5,6,7,8,9},{10,11,12,13}};
myFuntion(array);
return 0;
}
In function 'int main()':
Line 5: error: declaration of 'array' as multidimensional array must have bounds for all dimensions except the first
compilation terminated due to -Wfatal-errors.
Can anybody clear my doubt regarding this and some docs if possible for my more doubts.

void myFunction(int arr[][4])
you can put any number in the first [] but the compiler will ignore it. When passing a vector as parameter you must specify all dimensions but the first one.

You should at least specify the size of your second dimension.
int array[][5] = { { 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 }, { 10, 11, 12, 13 } };
There is also an error which is often repeated. To pass a 2D array as argument, you have to use the following types:
void myFuntion(int (*array)[SIZE2]);
/* or */
void myFuntion(int array[SIZE1][SIZE2]);

Why don't use std::vector instead of "raw" arrays. Advantages:
1. It can dynamically grow.
2. There is no issues about passing arguments to the function. I.e. try to call void myFuntion(int array[SIZE1][SIZE2]); with array, that has some different sizes not SIZE1 and SIZE2

Another templated solution would be:
template<int M, int N>
void myFunction(int array[N][M])
{
}

#include<iostream>
void myFuntion(int arr[3][4]);
int main()
{
int array[3][4]= {{1,2,3,4},{5,6,7,8},{10,11,12,13}};
myFuntion(array);
return 0;
}
void myFuntion(int arr[3][4])
{
}
http://liveworkspace.org/code/0ae51e7f931c39e4f54b1ca36441de4e

declaration of ‘array’ as multidimensional array must have bounds for all dimensions except the first
So you have to give
array[][size] //here you must to give size for 2nd or more
For passing the array in function , array is not a pointer to a pointer but it's pointer to an array so you write like this
fun(int (*array)[])
Here if you miss the parenthesis around (*array) then it will be an array of pointers
because of precedence of operators [] has higher precedence to *

Related

Why does a two-dimensional array become a one-dimensional array after passing it to a function?(C++

I'm making a simple Snake game. When making a map, my definition of the map is as follows
int map[25][25] = { 0 };
for (int i = 0; i < 25; i++)//Set the boundary to - 2
{
map[0][i] = -2;
map[24][i] = -2;
}
for (int i = 1; i < 25; i++)//Set the boundary to - 2
{
map[i][0] = -2;
map[i][24] = -2;
}
Then I made a function to simulate the motion of the snake。(The first parameter is the class I created: snake,The second is its moving direction. The key is the third parameter, the map array I put in.)
void snake_move(Snake snake1, int direction, int map[][25])
Then I made a call to the function.(The third parameter is the two-dimensional array pointer I passed in)
snake_move(snake1, direction, map);
Then the following figure appears
I found that it was a two-dimensional array before the function call,which is as follows
Why does this happen and how to solve this problem? I look forward to your reply・v・
You cannot pass built-in arrays like this to functions. snake_move(), even though it appears to have an argument that looks like a 2D array, it actually takes a pointer to a 1D array. This:
void func(int map[][25]);
Is actually equivalent to:
void func(int (*map)[25]);
map is a pointer to an array of 25 int elements. When you call that function:
func(map);
The map array "decays" to a pointer that points to its first element.
This is an unfortunate consequence of C++'s compatibility with C.
To avoid issues like this, use std::array (for fixed-size, static allocation of elements), or std::vector (for dynamically allocated elements.)
To get a 2D array, you need to use an array of arrays or a vector of vectors. For an array, that means:
std::array<std::array<int, 25>, 25>
This means "an array containing 25 arrays of 25 int elements.
It's a good idea to make snake_move take a const reference to avoid an unnecessary copy of the whole array. So:
#include <array>
void snake_move(
Snake snake1, int direction,
const std::array<std::array<int, 25>, 25>& map);
// ...
std::array<std::array<int, 25>, 25> map{};
for (int i = 0; i < 25; i++) {
map[0][i] = -2;
map[24][i] = -2;
}
for (int i = 1; i < 25; i++) {
map[i][0] = -2;
map[i][24] = -2;
}
snake_move(snake1, direction, map);
If snake_move() needs to modify the passed array, then remove the const.
To reduce the need to write the type over and over again, you can use an alias (with the using keyword):
using MapType = std::array<std::array<int, 25>, 25>;
void snake_move(Snake snake1, int direction, const MapType& map);
// ...
MapType map{};
// ...
The {} in the map declaration will initialize all values to zero. You can also use:
MapType map = {};
which does the same.
You can actually keep the dimension without using std::array
void snake_move(Snake snake1, int direction, int (&map)[25][25]);
https://godbolt.org/z/EYz7hzjTj
Also note it's not a 1D array (i.e. map[0] is not -2), the debug window does recognize and shows it's a int[25]*, it probably just have some bug that fail to display it in the correct format.
Why does this happen
Because of type decay. In particular, in many contexts (including when appearing as a parameter to a function), an array decays to a pointer to its first element. For example:
The type int [6] decays to int*
The type int *[6] decays to int**.
The type double [10] decays to double*.
The type int [5][6] decays to int (*)[6].
Thus, in you example, the third parameter int map[][25] is actually a pointer to an array of size 25 with elements of type int, ie int (*)[25].
how to solve this problem?
You can use std::array, as shown below:
void snake_move(Snake snake1, int direction,
//----------------------------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv------->std::array used
std::array<std::array<int, 25>,25> map)
{
}
std::array<std::array<int, 25>,25> map; //sta::array used
If the function snake_move() doesn't change the passed std::array, and to avoid unnecessary copying, you can take the std::array as a reference to const:
void snake_move(Snake snake1, int direction,
const std::array<std::array<int, 25>,25>& map)
//----------------------------^^^^^-----------------------------------^----->lvalue reference to non-const std::array<std::array<int, 25>,25>
{
}

C++ determine size of array [duplicate]

I am trying to write a function that prints out the elements in an array. However when I work with the arrays that are passed, I don't know how to iterate over the array.
void
print_array(int* b)
{
int sizeof_b = sizeof(b) / sizeof(b[0]);
int i;
for (i = 0; i < sizeof_b; i++)
{
printf("%d", b[i]);
}
}
What is the best way to do iterate over the passed array?
You need to also pass the size of the array to the function.
When you pass in the array to your function, you are really passing in the address of the first element in that array. So the pointer is only pointing to the first element once inside your function.
Since memory in the array is continuous though, you can still use pointer arithmetic such as (b+1) to point to the second element or equivalently b[1]
void print_array(int* b, int num_elements)
{
for (int i = 0; i < num_elements; i++)
{
printf("%d", b[i]);
}
}
This trick only works with arrays not pointers:
sizeof(b) / sizeof(b[0])
... and arrays are not the same as pointers.
Why don't you use function templates for this (C++)?
template<class T, int N> void f(T (&r)[N]){
}
int main(){
int buf[10];
f(buf);
}
EDIT 2:
The qn now appears to have C tag and the C++ tag is removed.
For C, you have to pass the length (number of elements)of the array.
For C++, you can pass the length, BUT, if you have access to C++0x, BETTER is to use std::array. See here and here. It carries the length, and provides check for out-of-bound if you access elements using the at() member function.
In C99, you can require that an array an array has at least n elements thusly:
void print_array(int b[static n]);
6.7.5.3.7: A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
In GCC you can pass the size of an array implicitly like this:
void print_array(int n, int b[n]);
You could try this...
#include <cstdio>
void
print_array(int b[], size_t N)
{
for (int i = 0; i < N; ++i)
printf("%d ", b[i]);
printf("\n");
}
template <size_t N>
inline void
print_array(int (&b)[N])
{
// could have loop here, but inline forwarding to
// single function eliminates code bloat...
print_array(b, N);
}
int main()
{
int a[] = { 1, 2 };
int b[] = { };
int c[] = { 1, 2, 3, 4, 5 };
print_array(a);
// print_array(b);
print_array(c);
}
...interestingly b doesn't work...
array_size.cc: In function `int main()':
array_size.cc:19: error: no matching function for call to `print_array(int[0u])'
JoshD points out in comments below the issue re 0 sized arrays (a GCC extension), and the size inference above.
In c++ you can also use a some type of list class implemented as an array with a size method or as a struct with a size member(in c or c++).
Use variable to pass the size of array.
int sizeof_b = sizeof(b) / sizeof(b[0]); does nothing but getting the pre-declared array size, which is known, and you could have passed it as an argument; for instance, void print_array(int*b, int size). size could be the user-defined size too.
int sizeof_b = sizeof(b) / sizeof(b[0]); will cause redundant iteration when the number of elements is less than the pre-declared array-size.
The question has already some good answers, for example the second one. However there is a lack of explanation so I would like to extend the sample and explain it:
Using template and template parameters and in this case None-Type Template parameters makes it possible to get the size of a fixed array with any type.
Assume you have such a function template:
template<typename T, int S>
int getSizeOfArray(T (&arr)[S]) {
return S;
}
The template is clearly for any type(here T) and a fixed integer(S).
The function as you see takes a reference to an array of S objects of type T, as you know in C++ you cannot pass arrays to functions by value but by reference so the function has to take a reference.
Now if u use it like this:
int i_arr[] = { 3, 8, 90, -1 };
std::cout << "number f elements in Array: " << getSizeOfArray(i_arr) << std::endl;
The compiler will implicitly instantiate the template function and detect the arguments, so the S here is 4 which is returned and printed to output.

how can I have a function with a 2D array as an argument whereas the array has a parameter/dimension that I want to change?

(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.

Range-for-statement cannot build range expression with array function parameter

Why cannot build range expression passing an array as a function argument and using in a range-for-statement.
Thanks for the help
void increment(int v[]){
// No problem
int w[10] = {9,8,7,6,5,4,3,2,1,9};
for(int& x:w){
std::cout<<"range-for-statement: "<<++x<<"\n";
}
// error: cannot build range expression with array function
// parameter 'v' since parameter with array type 'int []' is
// treated as pointer type 'int *'
for(int x:v){
std::cout<<"printing "<<x<<"\n";
}
// No problem
for (int i = 0; i < 10; i++){
int* p = &v[i];
}
}
int main()
{
int v[10] = {9,8,7,6,5,4,3,2,1,9};
increment(v);
}
Despite appearances, v is a pointer not an array - as the error message says. Built-in arrays are weird things, which can't be copied or passed by value, and silently turn into pointers at awkward moments.
There is no way to know the size of the array it points to, so no way to generate a loop to iterate over it. Options include:
use a proper range-style container, like std::array or std::vector
pass the size of the array as an extra argument, and interate with an old-school loop
It's because of the way you pass the array to the function. As written it decays to pointer. Try
template<int N>
void increment(int (&v)[N])
{
for (int x : v) std::cout << "printing " << x << "\n";
}
int main()
{
int v[10] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 9 };
increment(v);
}
This runs because a reference to an array of N ints is passed in the function and (unlike pointers) range for loops can iterate on those.
The function parameter int v[] is adjasted to int * Pointers do not keep information whether they point a single object or the first object of a sequence of objects.
The range-based for statement in fact uses the same expressions as standard functions std::begin and std::end They cannot be defined for pointers without knowing the size of the array. They can be defined for arrays, not pointers.

c++ dynamic size of the array

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]
}
}