Array as argument to function - c++

Here in f() I accept array to be of maximum size 4 but it still runs fine when I pass an array of size greater than 4(here 10), I know arrays in c++ are passed as pointers by default but than when is this method of passing array useful?
#include<iostream>
using namespace std;
void f(int a[4]){
for(int i = 0;i < 3;i++){
a[i] += 10;
}
}
int main(){
int a[10];
for(int i = 0;i < 10;i++)
a[i] = i;
f(a);
for(int i =0 ;i < 10;i++){
cout<<a[i]<<" ";
}
cout<<"\n";
return 0;
}
output: 10 11 12 3 4 5 6 7 8 9

I know arrays in c++ are passed as pointers by default
Correct.
This:
void foo(int a[4])
is literally rewritten to this:
void foo(int* a)
… and then when you call the function your array's name decays to the pointer, matching the rewritten/"real" argument type.
So you're not really passing an array at all.
When is this method of passing array useful?
Never.
This is a shameful oddity inherited from C. One might argue that the [4] is a useful hint to the developer that the pointed-to array "should" have four elements, but modern wisdom is that this is just unnecessarily and dangerously misleading.
Better alternatives include:
Pointer/size pair (two arguments): this is not less dangerous per se, but at least it does not lie about the type and lull you into a false sense of security!
Array by reference: lovely jubbly, but less flexible
std::array<int, 4> (by reference): as above, but neater

Either make f() more restrictive as shown by #songyuanyao or consider using a C++ std::array instead:
#include <iostream>
#include <array>
// make an alias for the array you'd like to accept
using myarray_t = std::array<int, 4>;
// accept the array by reference
void f(myarray_t& a) {
// use a range based for loop to access elements by reference
for(int& a_i : a) a_i += 10;
}
int main() {
// declare your array
myarray_t a;
for(size_t i = 0; i < a.size(); ++i) a[i] = static_cast<int>(i);
f(a);
// and you can use a range based for loop to extract by value too
for(int a__i : a)
std::cout << a_i << " ";
std::cout << "\n";
return 0;
}

If you want to impose restrictions on the size of the array passed in, you can change to pass-by-reference.
void f(int (&a)[4]){
for(int i = 0;i < 3;i++){
a[i] += 10;
}
}
void f(int a[4]) is same as void f(int* a); that means you can pass the array with any size which will decay to pointer (i.e. int*) when being passed.

Related

Is it possible to pass an array into a function as a parameter without creating a variable for that array?

So I made a function that takes arrays as parameters and I've tried calling the function by passing arrays that have not been defined as variables into said function (like {0,0,0,0}). However, I am given an error which says "too many initializer values."
Say we have a function defined as:
int func(int values[]) {
int average = 0;
for(int x = 0; x < values.size(); x++) {
average += values[x];
}
return average / values.size();
}
And we want to call it without defining an array to pass in like this: func({1,6,7,2});
Is there any way to do something like this or would I have to define an array and pass it into the function that way?
You cannot do that using built-in arrays. The fact that Arrays are neither Assignable nor Copy-able. Also They are not classes so they don't have member functions like size() or they take Initializer-list.
You can achieve that through using std::array if the size is constant or using std::vector if the size if dynamic.
#include <array>
int func(const std::array<int, 5>& values) {
int average = 0;
for (size_t x{}, sz{ values.size() }; x != sz ; ++x)
average += values[x];
return average / values.size();
}
int main() {
auto ret{
func({ 1, 6, 7, 2 })
};
std::cout << ret << std::endl;
}
Also don't mix Unsigned with Signed in calculations like in your loop:
for(int x = 0; x < values.size(); x++) // x is int while values.size() is unsigned int.
int func(const std::array<int, 5>& values): pass by reference to avoid the copy especially if the size is big. Also pass by const as long as the function doesn't intend to change the parameter also another benefit of using const reference is you can pass literals instead of an object.
N.B: I recommend to also to use range-based for because it is really relevant in your example as long as you want to iterate over all the elements and not intending to insert nor to delete elements:
int average = 0;
for (const auto& e : values)
average += e;
Another version of func as #M.M pointed out is to use std::accumalate to do the job for you:
int func(const std::array<int, 5>& values) {
return std::accumulate(values.begin(), values.end(), 0) /
values.size();
}
Using a vector, yes:
#include <vector>
using namespace std;
void f( const vector <int> & v ) {
}
int main() {
f( {1,2,3,4} );
}
Arrays don't work like that. When you pass an array to a function, the address of the first element gets passed like a pointer, and inside the function there is no more information about the size of the array. (Before the compiler itself could infer the size because the array was declared in the scope, but a function can be called from any number of places)
If you want to do something like that you would either have to use a container class, such as a vector, or you could pass a second argument into the function stating the size of the array. Another way is to have some sort of end point in your array, such as is the case with c-strings, for example a null value.

Why can't we pass int array[] to hoo(int* &p)?

In my understanding array in int array[]={1,2,3,4,5} is just a pointer to the first element of array. It means that array can be assigned to a pointer ptr of type int*.
Parameter int* &p in hoo will pass the argument by reference. It means we can change the passed argument to point to another value from within the hoo.
void hoo(int* &p, int n)
{
for (int i = 0; i < n; i++)
cout << p[i] << endl;
}
int main()
{
int array[] = { 1,2,3,4,5 };
// I can do this
int* ptr = array;
hoo(ptr, 5);
// but not this.
//hoo(array, 5);
}
Question
Why can't we pass int array to hoo without ptr ?
In my understanding array in int array[]={1,2,3,4,5} is just a pointer to the first element of array.
This is not correct. Arrays are arrays and pointers are pointers. They are distinct types with distinct properties. They are often confused because an array has the property that it will eagerly decay to a pointer to its first element.
hoo(array, 5); tries to convert array to an int* but the result of that conversion is an rvalue and can't be bound to a non-const reference. If, for example, you changed hoo to take a const reference it will compile fine :
void hoo(int* const &p, int n) { }
int main()
{
int array[] = { 1,2,3,4,5 };
hoo(array, 5);
}
In that case, you cannot change what p points to, making the use of a reference pointless.
When a function takes an int* & parameter, that is, a (non-move) reference to a pointer-to-an-int - then there needs to be a bona fide pointer variable to which that reference is referring. It can't be a temporary pointer value. Thus you can't do:
int x;
hoo(&x, 123);
because there's no pointer variable to refer to - just the temporary. It's essentially the same thing with your int[5]. There isn't actually an int* variable anywhere - there are just 5 ints. When you pass array to hoo(), what C++ does with that identifier is an array-to-pointer decay: It actually passes &(array[0]). So just like in the previous case, that won't compile.
The other answers already explain the problem. I want to suggest a change of coding practice.
Use of void hoo(int* &p, int n) as function declaration is very very old style. Using templates, you can let the compiler deduce the size and get a reference to the array, which obviates the need for using a pointer.
template <size_t N>
void hoo( int (&p)[N]) // The argument is a reference to an array of N elements.
{
for (int i = 0; i < N; i++)
cout << p[i] << endl;
}
The call to the function becomes natural.
int array[] = { 1,2,3,4,5 };
hoo(array);
If your function needs to be able to support dynamically allocated arrays as well, you can overload the function as follows.
void hoo(int* p, size_t N)
{
for (int i = 0; i < N; i++)
cout << p[i] << endl;
}
template <size_t N>
void hoo( int (&p)[N]) // The argument is a reference to an array of N elements.
{
hoo(p, N);
}

Why can't functions change vectors when they can change arrays?

I am trying to move from arrays to vectors in cpp for problem-solving and its overall benefits. I am facing some issues here even though this logic works on arrays.
#include <iostream>
#include <vector>
using namespace std;
void PrintArray(vector<int> v) { // O(n)
for (int i=0; i<v.size(); i++)
cout << v[i] << " ";
cout << endl;
}
void LF1(vector<int> A) { // O(n)
int temp = A[0],i;
for (i=0; i<A.size()-1; i++)
A.at(i) = A.at(i+1);
A.at(i)=temp;
// PrintArray(A); <-- shows updated array here
}
void LF(vector<int> A, int d) {
d = d % (A.size());
cout << "d%n: " << d << endl;
for (int j=0; j<d; j++)
LF1(A);
PrintArray(A);
}
int main(int argc, char const *argv[]) {
vector<int> A;
int d;
for(int i=1; i<6; i++)
A.push_back(i);
PrintArray(A);
cout << "Enter number of Left rotations to perform : ";
cin >> d;
LF(A,d);
return 0;
}
Problem 1: When I am calling LF1 inside of LF it returns the same array without rotating but when I write the code for LF1 inside of LF it seems to rotate.
Problem 2: The PrintArray() prints the rotated array only when called from LF1() or just immediately after its code when written (instead of calling LF1()) in LF() when causes it to print the array d times. Where d is the required rotations.
Regarding what you're doing wrong...you are passing the vectors by value. You don't expect changes to an integer to affect it in the caller when you pass it as a value...
void SomeFunction(int i) {
i = i + 1;
printf("Inside SomeFunction %d\n", i); // changed, 11
}
int i = 10;
SomeFunction(i);
printf("Outside SomeFunction %d\n", i); // unchanged, 10
...if you wanted to see a change, you would have to pass a pointer, such as int *pi, and then update it as *pi = *pi + 1;
The same principle applies to vectors and other C++ classes. If you just pass it as a value, the whole vector is copied. (Well, if it needs to be, a temporary could just be reused). But for now think of it as being copied: just as there's a difference between passing an integer and a pointer-to-an-integer, there's a difference between a vector and a pointer-to-a-vector.
You could pass a pointer to the vector if you intend to change it...or... C++ offers another tool called the reference, where references are very much like pointers but with a few differences. If you just changed your arguments to vector<int> &A then your code should work, because the arrays would be "passed by reference" instead of getting copied when they are "passed by value", so changes would take effect. If you don't want a function to need to be able to modify an array but still want to avoid the copy, pass by const reference, e.g. const vector<int> &A (e.g. this is what your PrintArray() should use).
You might not want to get too hung up on the details of references for now, other than thinking of it as a "convenient kind of pointer where you don't have to put the * on all the places you want to dereference". But in case you want to know more specifics:
What are the differences between a pointer variable and a reference variable in C++?
I am facing some issues here even though this logic works on arrays.
And this is probably the source of your confusion. Which comes from the fact that C-style arrays decay into pointers under the hood:
Passing an Array by reference in C
I think that's something that it's reasonable to be confused by, given that other types (such as integers and vectors) don't. It's just a quirk of C, that C++ inherited. So when C++11 wanted to clean that up, a wrapper class called std::array was introduced:
https://embeddedartistry.com/blog/2017/6/28/an-introduction-to-stdarray
https://en.cppreference.com/w/cpp/container/array
But C++ also has an algorithm to do rotation...
So if you want to see a good example of how this would be done, it's a place to start:
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::vector<int> v{1, 2, 3, 4};
std::rotate(v.begin(), v.begin() + 1, v.end());
for (auto &i : v)
std::cout << i << " ";
std::cout << "\n";
}
That will get you 2 3 4 1. The documentation has other examples, read through:
https://en.cppreference.com/w/cpp/algorithm/rotate

Passing and modifying array of vectors through functions in c++

(I'm from C background and new in C++ and its STLs)
I'm writing a C++ array of vectors that will be passed (as a reference of an array of vectors) through a function and will be processed in it.
In this case [in C] I would have passed a pointer to my custom data type (call by value under the hood.)
My code that's giving errors in compile time while trying to do so:
#include <cstdio>
#include <vector>
using namespace std;
/*
the problem is I can't get the syntax. vector<type> &var is
a reference to a single dimension array of vectors.
*/
void pass_arrayOf_vect(vector<int> &array, int lmt);
int main() {
int lmt = 10;
vector<int> lst[lmt];
pass_arrayOf_vect(lst, lmt);
return 0;
}
/*
and the traditional ambiguity of whether using "." or "->" for
accessing or modifying indexes and their members.
*/
void pass_arrayOf_vect(vector<int> &lst, int lmt) {
for (int i = 0; i < lmt; i++) {
lst[i].push_back(i*i);
}
for (int i = 0; i < lmt; i++) {
printf("array[%d]: ", i);
for (int j = 0; j < lst[i].size(); j++) {
printf("%d ",lst[i][j]);
}
printf("\n");
}
printf("\n");
return;
}
In the main function the lst variable is an array of vectors. When you pass this to the pass_arrayOf_vect function you pass a pointer to the first element.
I.e. when you do
pass_arrayOf_vect(lst, lmt);
it's actually the same as doing
pass_arrayOf_vect(&lst[0], lmt);
So the function you call needs to accept a pointer to a vector as its first argument (not a reference):
void pass_arrayOf_vect(vector<int> *array, int lmt);
// ^
// Note use of asterisk instead of ampersand
An even better solution would be to use an std::array of vectors instead. Or if you're on an older compiler without support for std::array, or need the amount to be run-time configurable (in which case you can't use plain C-style arrays anyway), use a vector of vectors.

Passing array as function parameter in C++ [duplicate]

This question already has answers here:
When a function has a specific-size array parameter, why is it replaced with a pointer?
(3 answers)
Closed 7 years ago.
I am aware that an array can be passed to a function in quite a few ways.
#include <iostream>
#include <utility>
using namespace std;
pair<int, int> problem1(int a[]);
int main()
{
int a[] = { 10, 7, 3, 5, 8, 2, 9 };
pair<int, int> p = problem1(a);
cout << "Max =" << p.first << endl;
cout << "Min =" << p.second << endl;
getchar();
return 0;
}
pair<int,int> problem1(int a[])
{
int max = a[0], min = a[0], n = sizeof(a) / sizeof(int);
for (int i = 1; i < n; i++)
{
if (a[i]>max)
{
max = a[i];
}
if (a[i] < min)
{
min = a[i];
}
}
return make_pair(max,min);
}
My code above passes only the first element while it should be passing an array (or technically, a pointer to the array) and hence, the output is 10, 10 for both max and min (i.e. a[0] only).
What am I doing wrong, I guess this is the correct way.
The contents of the array are being passed to the function. The problem is:
n = sizeof(a) / sizeof(int)
Does not give you the size of the array. Once you pass an array to a function you can't get its size again.
Since you aren't using a dynamic array you can use a std::array which does remember its size.
You could also use:
template <int N>
void problem1(int (&a) [N])
{
int size = N;
//...
}
No, you simply cannot pass an array as a parameter in C or C++, at least not directly.
In this declaration:
pair<int, int> problem1(int a[]);
even though a appears to be defined as an array, the declaration is "adjusted" to a pointer to the element type, so the above really means:
pair<int, int> problem1(int* a);
Also, an expression of array type is, in most contexts, implicitly converted to a pointer to the array's initial element. (Exceptions include an array as the operand of sizeof or unary &). So in a call to the above function:
int arr[10];
problem1(arr);
the array expression arr is equivalent to &arr[0], and that address (pointer value) is what's passed to the function.
Of course you can write code that does the equivalent of passing an array. You can make the array a member of a structure (but then it has to be of fixed length). Or you can pass a pointer to the initial element and pass a separate parameter containing the actual length of the array object.
Or you can use one of the C++ standard library classes that implement array-like data structures; then the length can be taken directly from the parameter.
I highly recommend reading section 6 of the comp.lang.c FAQ, which covers arrays and pointers. It's applicable to C++ as well (though it doesn't mention the C++ standard library).
In C++ language a function parameter declared as int a[] is immediately interpreted as and is equivalent to int *a parameter. Which means that you are not passing an array to your function. You are passing a pointer to the first element of an array.
Trying to apply the sizeof(a) / sizeof(int) technique to a pointer is useless. It cannot possibly produce the size of the argument arraay.
One alternative that hasn't been mentioned is writing your code as a template, and passing the array by reference so the template can deduce the size of the array:
template <class T, size_t n>
pair<T, T> problem1(T(&a)[n]) {
T max = a[0], min = a[0];
for (size_t i = 1; i < n; i++) {
if (a[i]>max) {
max = a[i];
}
if (a[i] < min) {
min = a[i];
}
}
return make_pair(max, min);
}
Note, however, that this will only work if you pass a real array, not a pointer. For example, code like this:
int *b = new int[10];
for (int i = 0; i < 10; i++)
b[i] = rand();
auto result = problem1(b);
...won't compile at all (because we've defined problem1 to receive a reference to an array, and b is a pointer, not an array).