I have a recursive function that takes a 2D array as a parameter in C++. The contents of this 2D array are to be unique among all recursive calls of this function.
I would like to modify this array each time before I make the recursive call. How can I do this without modifying the array for both of the 2 recursive calls, just for the current call?
Here is what I am trying to accomplish:
void foo(int a[10][10]) {
// imagine base case above
// modify array, i.e. set a[2][2] to '5'
foo(a);
// modify array i.e. set a[2][2] to '3'
foo(a);
}
I tried the following, which resulted in a compiler error:
void foo(int a[10][10]) {
// imagine base case above
foo(a[2][2] = 5);
foo(a[2][2] = 3);
}
The idea is that I want the array to be independent among recursive calls, for example, I don't want the set a[2][2] = 5 to apply to the next recursive call. I want that array modification to be "reverted", in a sense, before I apply the next modification (change).
This is easy to accomplish if I were just passing an int as an argument. For example, I could do:
void foo(int a) {
// imagine base case above
// increase a by 1
foo(a + 1);
// decrease a by 4
foo(a - 4);
}
You can see here how easy it is to make the modifications without affecting the following recursive call.
My question here is how I can make changes along the same lines with an array.
C-array cannot be copied, std::array can :)
So I would use std::array.
a[2][2] = 5 mutates array, whereas i - 4 doesn't mutate integer i (so nothing to discard in that case, contrary to f(i -= 4)).
there are no operator on array which allows easy customization,
we can create function or lambda for that:
// pass by value
std::array<std::array<int, 10>, 10>
mutated(std::array<std::array<int, 10>, 10> a, int x, int y, int value)
{
a[x][y] = value;
return a;
}
void foo(const std::array<std::array<int, 10>, 10>& a) {
// imagine base case above
// "modify" array, i.e. set a[2][2] to '5'
foo(mutated(a, 2, 2, 5));
// "modify" array i.e. set a[2][2] to '3'
foo(mutated(a, 2, 2, 3));
}
When you call foo(a + 1) in your last example, you are not passing the original integer, but a copy of it, to the function. To achieve something similar with arrays, you would have to create a copy of the entire array, and then modify the copy before passing it to the function.
Example
void foo(int a[10][10]) {
// Create two copies of a
// We cannot simply do 'int b[10][10] = a;', because that would make
// b point to the same memory region as a.
int b[10][10] = {0};
int c[10][10] = {0};
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
b[i][j] = a[i][j];
c[i][j] = a[i][j];
}
}
// Now that we have two copies of a, we can modify them separately
// and pass the mto the functions
// modify array, i.e. set [2][2] to '5'
b[2][2] = 5;
foo(b);
// modify array i.e. set [2][2] to '3'
c[2][2] = 3;
foo(c);
This function would eat memory fast, since it leads to infinite recursion and creates two new 100-element arrays for each function call. The manual copying of a could also be done using memcpy, but I wrote it out as a nested for loop for clarity.
Related
Given the following very basic function, how would I initialize arr to all random values, and how would I initialize arr to a set of given values, say the numbers 0-11?
void func() {
static int arr[2][2][3];
}
With my limited knowledge of static variables and C++ in general, I think that the static array needs to be initialized in one line, so when the function is called again, it does not get re-initialized. Basically, I want to say:
static int arr[2][2][3] = another_array
But this raises an error that 'another_array' is not an initializer list. I looked up initializer lists but they all included classes and other stuff I didn't understand. Is there any way to initialize this array? Any help is appreciated.
Technically if you try to assign the value of arr in a separate line, it will never be re-initialzied after the first time it was initialized. It will be re-assigned. But based on what you described, I assume that's the behavior you want to prevent.
So to initialized arr in the same line, what you could do is first create a function that will generate the desired number for you, then call that function many times during initializing arr:
int gen_num() {
// some code to return a random number for you...
}
void func() {
// I reduced `arr` to a 2D array, to make the code shorter. Making it a 3D array basically works the same
static int arr[2][3] = {{gen_num(), gen_num(), gen_num()}, {gen_num(), gen_num(), gen_num()}};
}
Note, if you make arr an std::array instead of the C-style array, then you can actually build up an array in a separate function, then just return the new array from that function:
std::array<std::array<int, 3>, 2> create_array()
{
std::array<std::array<int, 3>, 2> result;
// here you can assign each value separately
result[0][0] = 20;
result[2][1] = 10;
// or use for loop freely as needed
for(auto& arr : result)
{
for(auto& value : arr)
{
value = get_num();
}
}
return result;
}
void func() {
// Basically the same as having `int arr[2][3]`
static std::array<std::array<int, 3>, 2> arr = create_array();
}
I want to write a function which takes inArray[3] = {1,2,3,4} and an outArray[3], and modifies outArray[3] within the function to now contain values = {3,4,1,2}.
int main{
int inArray[4] = {1,2,3,4};
int outArray[4];
myFunction(&inArray, &outArray);
}
void myFunction(&inArray, &outArray){
outArray[0] = inArray[2];
outArray[1] = inArray[3];
outArray[2] = inArray[0];
outArray[3] = inArray[1];
}
I'm doing something wrong here, and I don't precisely understand how to pass an array by reference and manipulate the values inside the function.
The fiunction and its call can look the following way
const size_t N = 4;
void myFunction( int ( &inArray )[N], int ( &outArray )[N] )
{
outArray[0] = inArray[2];
outArray[1] = inArray[3];
outArray[2] = inArray[0];
outArray[3] = inArray[1];
}
int main()
{
int inArray[N] = {1,2,3,4};
int outArray[N];
myFunction( inArray, outArray );
}
Take into acccount that your definition of an array
int inArray[3] = {1,2,3,4};
contains a typo and will not be compiled. There must be at least like
int inArray[4] = {1,2,3,4};
or
int inArray[] = {1,2,3,4};
You arrays have size 3, but you try to store 4 elements in them and access the fourth element at [3] (which has undefined behaviour).
Make them bigger, either hardcoding 4 or making everything automatically adjust to the current length of the list of numbers you use to initialise inArray:
int inArray[] = {1,2,3,4}; // automatically sized
int outArray[sizeof inArray / sizeof *inArray];
Then, your function signature should specify the array-of-int of the arguments. There are many ways to do that:
void myFunction(const int inArray[], int outArray[]) // 1
void myFunction(const int* inArray, int* outArray) // 2
void myFunction(const int (&inArray)[4], int (&outArray)[4]) // 3
template <size_t N>
void myFunction(const int (&inArray)[N], int (&outArray)[N]) // 4
The first is clearly the simplest.
The second is equivalent, as when a caller passes array arguments they're allowed to decay to pointers, and that happens even for 1) as the array dimension can only be captured or enforced when accepting arrays by reference, as in the following cases...
The third additionally ensures the array parameters have exactly 4 elements (so suddenly you can't (easily) pass say an array of 10 elements and have it copy over only the first 4).
The fourth accepts any sizes of array, but if used from different calling code on different sized arrays it may create multiple copies of the myFunction code, potentially using more memory for a larger program.
As you're function body hardcodes operations on elements [0] to [3], it won't adjust to do things on elements further into larger arrays, but you have the option of using the N value inside the function body to work out how many elements to operate on.
Array are always passed by reference no need to pass it by reference manually.
I got this library of mathematical routines ( without documentation ) to work on some task at college. The problem I have with it is that all of its functions have void return type, although these functions call one another, or are part of another, and the results of their computations are needed.
This is a piece of ( simplified ) code extracted from the libraries. Don't bother about the mathematics in code, it is not significant. Just passing arguments and returning results is what puzzles me ( as described after code ) :
// first function
void vector_math // get the (output) vector we need
(
double inputV[3], // input vector
double outputV[3] // output vector
)
{
// some variable declarations and simple arithmetics
// .....
//
transposeM(matrix1, matrix2, 3, 3 ); // matrix2 is the result
matrixXvector( matrix2, inputV, outputV) // here you get the result, outputV
}
////////
// second function
void transposeM // transposes a matrix
(
std::vector< std::vector<double> > mat1, // input matrix
std::vector< std::vector<double> > &mat2, // transposed matrix
int mat1rows, int mat1columns
)
{
int row,col;
mat2.resize(mat1columns); // rows
for (std::vector< std::vector<double> >::iterator it=mat2.begin(); it !=mat2.end();++it)
it->resize(mat1rows);
for (row = 0; row < mat1rows; row++)
{
for (col = 0; col < mat1columns; col++)
mat2[col][row] = mat1[row][col];
}
}
////////
// third function
void matrixXvector // multiply matrix and vector
(
std::vector< std::vector<double> > inMatrix,
double inVect[3],
double outVect[3]
)
{
int row,col,ktr;
for (row = 0; row <= 2; row++)
{
outVect[row]= 0.0;
for (ktr = 0; ktr <= 2; ktr++)
outVect[row]= outVect[row] + inMatrix[row][ktr] * inVect[ktr];
}
}
So "vector_math" is being called by the main program. It takes inputV as input and the result should be outputV. However, outputV is one of the input arguments, and the function returns void. And similar process occurs later when calling "transposeM" and "matrixXvector".
Why is the output variable one of the input arguments ? How are the results being returned and used for further computation ? How this kind of passing and returning arguments works ?
Since I am a beginner and also have never seen this style of coding, I don't understand how passing parameters and especially giving output works in these functions. Therefore I don't know how to use them and what to expect of them ( what they will actually do ). So I would very much appreciate an explanation that will make these processes clear to me.
EXTRA :
Thank you all for great answers. It was first time I could barely decide which answer to accept, and even as I did it felt unfair to others. I would like to add an extra question though, if anyone is willing to answer ( as a comment is enough ). Does this "old" style of coding input/output arguments have its name or any other expression with which it is referred ?
This is an "old" (but still popular) style of returning certain or multiple values. It works like this:
void copy (const std::vector<double>& input, std::vector<double>& output) {
output = input;
}
int main () {
std::vector<double> old_vector {1,2,3,4,5}, new_vector;
copy (old_vector, new_vector); // new_vector now copy of old_vector
}
So basically you give the function one or multiple output parameter to write the result of its computation to.
If you pass input parameters (i.e. you don't intend to change them) by value or by const reference does not matter, although passing read only arguments by value might be costly performance-wise. In the first case, you copy the input object and use the copy in the function, in the latter you just let the function see the original and prevent it from being modified with the const. The const for the input parameters is optional, but leaving it out allows the function to change their values which might not be what you want, and inhibits passing temporaries as input.
The input parameter(s) have to be passed by non-const reference to allow the function to change it/them.
Another, even older and "C-isher" style is to passing output-pointer or raw-arrays, like the first of your functions does. This is potentially dangerous as the pointer might not point to a valid piece of memory, but still pretty wide spread. It works essentially just like the first example:
// Copies in to int pointed to by out
void copy (int in, int* out) {
*out = in;
}
// Copies int pointed to by in to int pointed to by out
void copy (const int* in, int* out) {
*out = *in;
}
// Copies length ints beginning from in to length ints beginning at out
void copy (const int* in, int* out, std::size_t length) {
// For loop for beginner, use std::copy IRL:
// std::copy(in, in + length, out);
for (std::size_t i = 0; i < length; ++i)
out[i] = in[i];
}
The arrays in your first example basically work like pointers.
Baum's answer is accurate, but perhaps not as detailed as a C/C++ beginner would like.
The actual argument values that go into a function are always passed by value (i.e. a bit pattern) and cannot be changed in a way that is readable by the caller. HOWEVER - and this is the key - those bits in the arguments may in fact be pointers (or references) that don't contain data directly, but rather contain a location in memory that contains the actual value.
Examples: in a function like this:
void foo(double x, double output) { output = x ^ 2; }
naming the output variable "output doesn't change anything - there is no way for the caller to get the result.
But like this:
void foo(double x, double& output) { output = x ^ 2; }
the "&" indicates that the output parameter is a reference to the memory location where the output should be stored. It's syntactic sugar in C++ that is equivalent to this 'C' code:
void foo(double x, double* pointer_to_output) { *pointer_to_output = x ^ 2; }
The pointer dereference is hidden by the reference syntax but the idea is the same.
Arrays perform a similar syntax trick, they are actually passed as pointers, so
void foo(double x[3], double output[3]) { ... }
and
void foo(double* x, double* output) { ... }
are essentially equivalent. Note that in either case there is no way to determine the size of the arrays. Therefore, it is generally considered good practice to pass pointers and lengths:
void foo(double* x, int xlen, double* output, int olen);
Output parameters like this are used in multiple cases. A common one is to return multiple values since the return type of a function can be only a single value. (While you can return an object that contains multiple members, but you can't return multiple separate values directly.)
Another reason why output parameters are used is speed. It's frequently faster to modify the output in place if the object in question is large and/or expensive to construct.
Another programming paradigm is to return a value that indicates the success/failure of the function and return calculated value(s) in output parameters. For example, much of the historic Windows API works this way.
An array is a low-level C++ construct. It is implicitly convertible to a pointer to the memory allocated for the array.
int a[] = {1, 2, 3, 4, 5};
int *p = a; // a can be converted to a pointer
assert(a[0] == *a);
assert(a[1] == *(a + 1));
assert(a[1] == p[1]);
// etc.
The confusing thing about arrays is that a function declaration void foo(int bar[]); is equivalent to void foo(int *bar);. So foo(a) doesn't copy the array a; instead, a is converted to a pointer and the pointer - not the memory - is then copied.
void foo(int bar[]) // could be rewritten as foo(int *bar)
{
bar[0] = 1; // could be rewritten as *(bar + 0) = 1;
}
int main()
{
int a[] = {0};
foo(a);
assert(a[0] == 1);
}
bar points to the same memory that a does so modifying the contents of array pointed to by bar is the same as modifying the contents of array a.
In C++ you can also pass objects by reference (Type &ref;). You can think of references as aliases for a given object. So if you write:
int a = 0;
int &b = a;
b = 1;
assert(a == 1);
b is effectively an alias for a - by modifying b you modify a and vice versa. Functions can also take arguments by reference:
void foo(int &bar)
{
bar = 1;
}
int main()
{
int a = 0;
foo(a);
assert(a == 1);
}
Again, bar is little more than an alias for a, so by modifying bar you will also modify a.
The library of mathematical routines you have is using these features to store results in an input variable. It does so to avoid copies and ease memory management. As mentioned by #Baum mit Augen, the method can also be used as a way to return multiple values.
Consider this code:
vector<int> foo(const vector<int> &bar)
{
vector<int> result;
// calculate the result
return result;
}
While returning result, foo will make a copy of the vector, and depending on number (and size) of elements stored the copy can be very expensive.
Note:
Most compilers will elide the copy in the code above using Named Return Value Optimization (NRVO). In general case, though, you have no guarantee of it happening.
Another way to avoid expensive copies is to create the result object on heap, and return a pointer to the allocated memory:
vector<int> *foo(const vector<int> &bar)
{
vector<int> *result = new vector<int>;
// calculate the result
return result;
}
The caller needs to manage the lifetime of the returned object, calling delete when it's no longer needed. Faililng to do so can result in a memory leak (the memory stays allocated, but effectively unusable, by the application).
Note:
There are various solutions to help with returning (expensive to copy) objects. C++03 has std::auto_ptr wrapper to help with lifetime management of objects created on heap. C++11 adds move semantics to the language, which allow to efficiently return objects by value instead of using pointers.
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.
I'm relatively new to C++ and am having a tough time passing my array into a separate function. Apologies for re-asking a question that has no doubt been answered a dozen times before, but I couldn't find any questions similar to the problem I have with my code.
int main()
{
Array<int> intarray(10);
int grow_size = 0;
intarray[0] = 42;
intarray[1] = 12;
intarray[9] = 88;
intarray.Resize(intarray.Size()+2);
intarray.Insert(10, 6);
addToArray(intarray);
int i = intarray[0];
for (i=0;i<intarray.Size();i++)
cout<<i<<'\t'<<intarray[i]<<endl;
Sleep(5000);
}
void addToArray(Array<int> intarray)
{
int newValue;
int newIndex;
cout<<"What do you want to add to the array?"<<endl;
cin >> newValue;
cout<<"At what point should this value be added?"<<endl;
cin >> newIndex;
intarray.Insert(newValue, newIndex);
}
You are passing a copy of the array, so any changes will not affect the original. Pass by reference instead:
void addToArray(Array<int> &intarray)
// ^
This is a special case of a more general question on parameters passing.
You may want to consider the following guidelines:
If you want to pass something to a function to modify it inside the function (and make the changes visible to the caller), pass by reference (&).
e.g.
// 'a' and 'b' are modified inside function's body,
// and the modifications should be visible to the caller.
//
// ---> Pass 'a' and 'b' by reference (&)
//
void Swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
If you want to pass something that is cheap to copy (e.g. an int, a double, etc.) to a function to observe it inside the function, you can simply pass by value.
e.g.
// 'side' is an input parameter, "observed" by the function.
// Moreover, it's cheap to copy, so pass by value.
//
inline double AreaOfSquare(double side)
{
return side*side;
}
If you want to pass something that is not cheap to copy (e.g. a std::string, std::vector, etc.) to a function to observe it inside the function (without modifying it), you can pass by const reference (const &).
e.g.
// 'data' is an input parameter, "observed" by the function.
// It is in general not cheap to copy (the vector can store
// hundreds or thousands of values), so pass by const reference.
//
double AverageOfValues(const std::vector<double> & data)
{
if (data.empty())
throw std::invalid_argument("Data vector is empty.");
double sum = data[0];
for (size_t i = 1; i < data.size(); ++i)
sum += data[i];
return sum / data.size();
}
In modern C++11/14 there is also an additional rule (related to move semantics): if you want to pass something that is cheap to move and make a local copy of it, then pass by value and std::move from the value.
e.g.
// 'std::vector' is cheap to move, and the function needs a local copy of it.
// So: pass by value, and std::move from the value.
//
std::vector<double> Negate(std::vector<double> v)
{
std::vector<double> result( std::move(v) );
for (auto & x : result)
x *= -1;
return result;
}
Since in your addToArray() function you modify the Array<int> argument, and you want modifications visible to the caller, you can apply rule #1, and pass by reference (&):
void addToArray(Array<int> & intarray)
My suggestion is use pointer, as usual declare the function
void yourFunction(int * arrayPointer);
In main() function you should input
int yourArray[8] = {11, -2, 45, 37, 18, 35};
int * arrayPointer = &yourFunction[0];
yourFunction(yourArray); // call your function
Finally in yourFunction()
void yourFunction(int * arrayPointer)
{
// print all number in the array
for(int x = 0; x < 6; x++)
{
cout << *arrayPointer << " ";
arrayPointer++;
}
}
This at least work for me, hope this will help