How can I pass a given std::vector<float> to a function to match the parameter type float (*parameter)[3]?
The function fills the parameter with coordinates of 3d points, that's the reason for the parameter type to be an array of 3-elements-long arrays. The function is provided by a library and I cannot change it.
I already initialized vector to cover enough elements.
void f(float (*parameter)[3])
{
}
int main()
{
vector<float> v(3);
f(reinterpret_cast<float(*)[3]>(&v[0]));
}
Because there is no way to ascertain that an std::allocator<T> involves in some configuration a float[3], it is not possible to point to such an array given an std::vector<T>. It is not a matter of finding the right cast, or the right value to cast.
The matter is that something like the function you described can only ever be passed a pointer to an actual float[3], or a null pointer.
The only strictly conformant thing you can do is to copy the data to and from a bona-fide float[3] variable, passing a pointer to it to your function.
Related
A function accepts a value of type int[][26], however, I am unable to define a variable of this type.
void A(int abc[][26]);
I have tried the following
int abc[][26] (can't compile)
int (*abc)[26] (segmentation fault)
How do I define such a variable/
Thanks a lot
Basically you don't. int abc[][26] will take any 2d array of the form int[N][26].
When you work with arrays as function parameters the array decays to a pointer. That means the top most dimension is not needed since it decays to a pointer of the type of elements in the array. So, if you have
void foo(int[10])
what you really have is
void foo(int*)
since it doesn't matter how many elements there are. When you have
void foo(int[10][26])
//or
void foo(int[][26])
then you get
void foo(int(*)[26])
Since the array holds arrays we get a pointer to an array since it doesn't matter how many arrays the pointer points to, we just need to know it points to a int[26].
How do I define variable of type int[][26]?
int[][26] is an array of unknown bound. You cannot define variables of such type.
Arrays of unknown bound can are typically used in contexts where the type is adjusted to be something else. For example, in a function argument list, an array is adjusted to be a pointer to an element of such array. The following are equivalent due to type adjustment:
void A(int abc[][26]);
void A(int (*abc)[26]);
// adjusted argument type is int(*)[26]
Another example of such adjustment is definition of a variable, where the bound is deduced from the initialiser. The following are equivalent due to type adjustment:
int arr[][26] = {{}, {}};
int arr[2][26] = {};
// adjusted array type is int[2][26]
A use case for arrays of unknown bound where the type is not adjusted is in templates, where explicitly providing such array as template type argument can be used to signify that a pointer is to an element in an array, rather than a singular object. For example, std::allocator<int>::deallocate will invoke delete while std::allocator<int[]>::deallocate will invoke delete[].
I have an array of vectors (of ints) and I want to pass it to a member function as reference so it can be modified. (It actually is the output of my function but I already have a return value.)
I wrote something like this
int Dag::dag2array(vector<int> (&aVectors)[4])
{
//some stuff
//calling another function tree2array(aVectors)
//passing the same array as reference
}
It compile and runs although it looks like it is not doing what I want.
In a more or less opposite question (Passing array of vectors as a function parameter (values will not change)), the answers say that the array can be modified without & and that it does not make a copy but it is like a pointer.
Why for a variable like an int one needs the & to avoid
copying and to be able to modify the value of the original variable "on the fly" and not for an array?
Should I use the & or not in my case?
This is one of those cases where C arrays just make life difficult. I would strongly recommend using a std::array (or std::tr1::array if you're not using C++11 yet). Rather than that obscure syntax, saying
int func(std::array<std::vector<int>, 4>& vectors)
makes it very clear that you're passing an array of 4 vectors by reference, and thus can modify the values by saying
vectors[1][2] = 19;
or what-have-you.
When an array is passed to a function, its type is adjusted to a pointer to its first element. Likewise a parameter declaration of the form T[N] is adjusted to T*. The pointer being passed is copied but the elements of the vector are not copied at all. This means when dereferencing the pointer you can still refer to the original array element through the array access syntax array[n] (which is really just pointer arithmetic: *(array + n)).
If you are passing an actual object to a function by value, a copy will occur so if you still want to modify the element you will need a reference.
So no, you do not need to pass the array by reference. Not unless you want to access the size of the array in the function (because the array-to-pointer decay discards the array size).
Is it possible to pass an array by value to a C++ function?
If it is, how would I do that?
If by array you mean raw array, then the answer is No. You cannot pass them by value either in C or C++.
Both the languages provide a workaround, where you can wrap a struct around that array and pass its object. Example:
struct MyArray { int a[100]; };
...
struct MyArray obj; // `obj.a[]` is the array of your interest
foo(obj); // you have passed the `a[]` by value
In C++, such structs are readily available in form of std::vector and std::array.
Definitely:
void foo(std::array<int, 42> x);
Normally passing an array to a function makes it decay to a pointer. You implicitly pass the (start-)address of the array to the function. So you actually can't pass an array by value. Why don't you use va_args if you want to pass the contents by value?
Yes, you can. You can implement it by using a pointer as the argument, but in the function body, you can use the copy mothord (the exact name I can't remember) to copy it.
How to find the size of string array passed to a function. The size should be computed inside the function.
#include<iostream>
using namespace std;
template <typename T,unsigned S>
unsigned arraysize(const T (&v)[S]) { return S; }
void func(string args[])
{
unsigned m=arraysize(args);
cout<<m;
}
int main()
{
string str_arr[]={"hello","foo","bar"};
func(str_arr);
}
What i dont understand is:
If the statement arraysize(str_arr) is used in main,it wouldn't pose a problem. The str_arr is an array, so str_arr acts as a pointer, so when we use arraysize(str_arr) that means we're sending the address to arraysize function.(correct me if i'm wrong).
But in function func(), i dont understand why there is a problem, i.e. the statement arraysize(args) sends the address of the string array args(or the address of pointer args).. or is it more complicated since it becomes some double pointer?? Explain?
Also please correct the above code..
str_arr is an array of strings. When you do sizeof(str_arr), you get the size of that array. However, despite the fact that args looks like an array of strings, it's not. An argument that looks like an array is really of pointer type. That is, string args[] is transformed to string* args by the compiler. When you do sizeof(args) you are simply getting the size of the pointer.
You can either pass the size of the array into the function or take a reference to the array with a template parameter size (as you did with arraysize):
template <size_t N>
void func(string (&args)[N])
{
// ...
}
There is no way to determine the size of an array when sent to a function. You also have to remember that only a pointer to the array is sent to the function, which makes it even theoretically quite implausible to calculate the array's size.
The information of the array's size is never visible in your function, as you threw it away when you decided to use string args[] for the argument. From the compiler's perspective, it's the same as string* args. You could change the function to:
template<size_t M>
void func(string (&args)[M])
{
cout<<M;
}
but it seems you already know that, right?
If the statement arraysize(str_arr) is used in main,it wouldn't pose a
problem. The str_arr is an array, so str_arr acts as a pointer, so
when we use arraysize(str_arr) that means we're sending the address to
arraysize function.(correct me if i'm wrong).
I have to correct you here. You state a correct premise, but draw the wrong conclusion.
The key point is indeed that str_arr is an array in main. While an array decays to a pointer in many (most) expression contexts, this does not apply when a reference to array is initialized. That is the reason why array_size is declared to take a reference to array parameter - this is the only way to have a parameter of array type, which implies that it comes with a defined length.
That is not the case for func. When a function parameter is declared to be of plain array type, the the array to pointer decay is applied to that declaraction. Your declaration of func is equivalent to void func(string * args). Thus args is a pointer, not an array. You could call func as
string str_non_array;
func(&str_non_array);
Because of this, a reference-to-array can't bind to it. And anyways, args has completely lost all information about the size of the array it is pointing to.
You could use the same reference-to-array trick as is used in arraysize: declare func as
template <std::size_t N>
void func(string (&args)[N]);
But this gets impractical to do everywhere (and may lead to code bloat, if applied naively to all array-handling code). The C++ equivalent of an array-with-length as available in other languages is std::vector<string> (for dynamically sized arrays) or std::array<string,N> (for fixed size known at compile time). Note that the latter can cause the same code bloat as mentioned above, so in most cases, std::vector<string> would be the preferred type for array that you need to pass to various functions.
Dmitry is right and I would like to explain it a bit further. The reason its happening is because array is not a First Class citizen in C++ and when passed as parameter it decays to pointer and what you get in called function is a pointer to its first element and size is lost.
You can refer C++ arrays as function arguments to see what alternative options are available.
I recently found some code like this:
typedef int TenInts[10];
void foo(TenInts &arr);
What can you do in the body of foo() that is useful, that you could not do if the declaration was:
void foo(int *arr); // or,
void foo(int arr[]); // or,
void foo(int arr[10]); // ?
I found a question that asks how to pass a reference to an array. I guess I am asking why.
Also, only one answer to "When is pointer to array useful?" discussed function parameters, so I don't think this is a duplicate question.
The reference-to-array parameter does not allow array type to decay to pointer type. i.e. the exact array type remains preserved inside the function. (For example, you can use the sizeof arr / sizeof *arr trick on the parameter and get the element count). The compiler will also perform type checking in order to make sure the array argument type is exactly the same as the array parameter type, i.e. if the parameter is declared as a array of 10 ints, the argument is required to be an array of exactly 10 ints and nothing else.
In fact, in situations when the array size is fixed at compile-time, using a reference-to-array (or pointer-to-array) parameter declarations can be preceived as the primary, preferred way to pass an array. The other variant (when the array type is allowed to decay to pointer type) are reserved for situations when it is necessary to pass arrays of run-time size.
For example, the correct way to pass an array of compile-time size to a function is
void foo(int (&arr)[10]); // reference to an array
or
void foo(int (*arr)[10]); // pointer to an array
An arguably incorrect way would be to use a "decayed" approach
void foo(int arr[]); // pointer to an element
// Bad practice!!!
The "decayed" approach should be normally reserved for arrays of run-time size and is normally accompanied by the actual size of the array in a separate parameter
void foo(int arr[], unsigned n); // pointer to an element
// Passing a run-time sized array
In other words, there's really no "why" question when it comes to reference-to-array (or pointer-to-array) passing. You are supposed to use this method naturally, by default, whenever you can, if the array size is fixed at compile-time. The "why" question should really arise when you use the "decayed" method of array passing. The "decayed" method is only supposed to be used as a specialized trick for passing arrays of run-time size.
The above is basically a direct consequence of a more generic principle. When you have a "heavy" object of type T, you normally pass it either by pointer T * or by reference T &. Arrays are no exception from this general principle. They have no reason to be.
Keep in mind though that in practice it is often makes sense to write functions that work with arrays of run-time size, especially when it comes to generic, library-level functions. Such functions are more versatile. That means that often there's a good reason to use the "decayed" approach in real life code, Nevertheless, this does not excuse the author of the code from recognizing the situations when the array size is known at compile time and using the reference-to-array method accordingly.
One difference is that it's (supposed to be) impossible to pass a null reference. So in theory the function does not need to check if the parameter is null, whereas an int *arr parameter could be passed null.
You can write a function template to find out the size of an array at compile time.
template<class E, size_t size>
size_t array_size(E(&)[size])
{
return size;
}
int main()
{
int test[] = {2, 3, 5, 7, 11, 13, 17, 19};
std::cout << array_size(test) << std::endl; // prints 8
}
No more sizeof(test) / sizeof(test[0]) for me ;-)
Shouldn't we also address the words in bold from the question:
What can you do in the body of foo() that is useful, that you could not do if the declaration was void foo(int arr[]);?
The answer is: nothing. Passing an argument by reference allows a function to change its value and pass back this change to the caller. However, it is not possible to change the value of the array as a whole, which would have been a reason to pass it by reference.
void foo(int (&arr)[3]) { // reference to an array
arr = {1, 2 ,3}; // ILLEGAL: array type int[3] is not assignable
arr = new(int[3]); // same issue
arr = arr2; // same issue, with arr2 global variable of type int[3]
}
You can ensure that the function is only called on int arrays of size 10. That may be useful from a type-checking standpoint.
You get more semantic meaning regarding what the function is expecting.