My question is: when i write a function prototype in C like this:
void foo(int *vector);
It's the same thing to do:
void foo(int vector[MAX_LENGTH]);
To the function, is passed always as a pointer? The code it's the same?
Thanks in advance.
This is subtle. Arrays in C are not pointers, but C does not allow arrays to be passed as function parameters. So when you have void foo(int vector[MAX_LENGTH]);, essentially all you're doing is telling other programmers (and your future self) that this function expects an array of MAX_LENGTH to be passed to it. The compiler won't help you. It will silently cast your array to a pointer.
This explains it pretty well.
Yes an array type is implicitly converted to a pointer type when passed to a function.
So
void foo(int *a) and void foo(int a[]) are identical.
You can easily check that using sizeof() operator inside the function definition
For example
void foo(int a[])
{
std::cout<<sizeof(a); //prints sizeof(int*)
}
int main()
{
int a[]={1,2,3,4};
foo(a);
}
EXTRA (Printing size of an array inside a function)
[C++ Only]
template<typename T,size_t n>
void size_of_array(T (&a)[n]) //Array passed by reference. Template argument deduction
{
std::cout<<sizeof(a); //prints sizeof(n*sizeof(int))
}
int main()
{
int a[]={1,2,3,4,5};
size_of_array(a);
}
This is one of the rough edges of the C language(s). Two declaration that look exactly the same (but for the names), one in the prototype and one as a stack variable, result in the declaration of two different types of variables.
void foo(int A[10]) {
int B[10];
}
Inside the scope of foo, A is pointer to int and B is array of ten elements of type int. As somebody else mentioned, even their sizes computed with sizeof are different.
C++ inherited the rule, so for your example code the prototypes of both functions should be the same.
C99 complicates this matter even further by introducing the new keyword static ;-)
void foo(int A[static 10]) {
int B[10];
}
this doesn't change the rules on how A and B are seen from the inside, but provides an information to the caller side of howmuch array elements are expected. For the moment gcc accepts this new syntax and simply ignores this information.
there's little else it could pass! the [] contraint lets the compiler do more checks though.
Related
How does passing a statically allocated array by reference work?
void foo(int (&myArray)[100])
{
}
int main()
{
int a[100];
foo(a);
}
Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference?
I don't understand separate parenthesis followed by big brackets here. Thanks.
It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.
EDIT: Some clarification.
void foo(int * x);
void foo(int x[100]);
void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use sizeof on x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
It's just the required syntax:
void Func(int (&myArray)[100])
^ Pass array of 100 int by reference the parameters name is myArray;
void Func(int* myArray)
^ Pass an array. Array decays to a pointer. Thus you lose size information.
void Func(int (*myFunc)(double))
^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.
It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.
E.g. int &myArray[100] // array of references
So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.
E.g int (&myArray)[100] // reference of an array of 100 ints
The following creates a generic function, taking an array of any size and of any type by reference:
template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
// do stuff
}
play with the code.
Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.
I'm still new to C++ and I've got a question concerning arrays as parameters in functions/ constructors. I've realized that it is possible to declare an array in two ways (maybe there are more, which I haven't seen before):
1.
void foo(int arr[]);
2.
void foo(int arr);
In both cases, arr can be used in the following way:
arr[0] = 1;
But what is the difference between those? Or is it just a matter of clarity?
The difference is one is a variable, the other an array.
void my_func(int array[]); // Function with array parameter.
void your_func(int variable); // Function with variable parameter.
The notation:
int v;
v[5] = 6;
should generate a compilation error or warning because the v variable is not an array nor a pointer.
How does passing a statically allocated array by reference work?
void foo(int (&myArray)[100])
{
}
int main()
{
int a[100];
foo(a);
}
Does (&myArray)[100] have any meaning or its just a syntax to pass any array by reference?
I don't understand separate parenthesis followed by big brackets here. Thanks.
It's a syntax for array references - you need to use (&array) to clarify to the compiler that you want a reference to an array, rather than the (invalid) array of references int & array[100];.
EDIT: Some clarification.
void foo(int * x);
void foo(int x[100]);
void foo(int x[]);
These three are different ways of declaring the same function. They're all treated as taking an int * parameter, you can pass any size array to them.
void foo(int (&x)[100]);
This only accepts arrays of 100 integers. You can safely use sizeof on x
void foo(int & x[100]); // error
This is parsed as an "array of references" - which isn't legal.
It's just the required syntax:
void Func(int (&myArray)[100])
^ Pass array of 100 int by reference the parameters name is myArray;
void Func(int* myArray)
^ Pass an array. Array decays to a pointer. Thus you lose size information.
void Func(int (*myFunc)(double))
^ Pass a function pointer. The function returns an int and takes a double. The parameter name is myFunc.
It is a syntax. In the function arguments int (&myArray)[100] parenthesis that enclose the &myArray are necessary. if you don't use them, you will be passing an array of references and that is because the subscript operator [] has higher precedence over the & operator.
E.g. int &myArray[100] // array of references
So, by using type construction () you tell the compiler that you want a reference to an array of 100 integers.
E.g int (&myArray)[100] // reference of an array of 100 ints
The following creates a generic function, taking an array of any size and of any type by reference:
template<typename T, std::size_t S>
void my_func(T (&arr)[S]) {
// do stuff
}
play with the code.
Arrays are default passed by pointers. You can try modifying an array inside a function call for better understanding.
I have a question about passing array with reference operator. I want to write code that pass array using reference operator. Then I tried
void swap(int &testarray[3]){
// code
}
It gives me error. It says,
/main.cpp:5: error: declaration of 'testarray' as array of references
However when changed my code with
void swap(int (&testarray)[3]){
// code
}
It runs properly. Only difference is having bracket.
Why it needs bracket and what is the difference between int (&testarray)[3] and int &testarray[3]
Thanks for helping.
void foo(int &testarray[3]) is interpreted as void foo((int &)testarray[3]) due to priority. And array of references are illegal.
Whereas void foo(int (&testarray)[3]) is interpreted as you want. (reference of an array of 3 int).
void foo(int testarray[3]) is equivalent to void foo(int testarray[])
which decays to void foo(int *testarray). (int pointer).
In fact this construction
int & testarray[3]
defines an array of references to integral objects. The C++ Standard does not allow to define arrays of references to objects.
Function overloading can happen between two member functions which have the same number of parameters, if one of them is declared as const.
But what if one function has a const argument, another has non-const argument of same type?
Will it work for references and pointers? If C++ provides it, why does it provide? Please share the reason with me if you know.
Below is the example that helps you in understanding the above scenario.
void fun(const int i)
{
cout << "fun(const int) called ";
}
void fun(int i)
{
cout << "fun(int ) called " ;
}
int main()
{
const int i = 10;
fun(i);
return 0;
}
Output: Compiler Error: redefinition of 'void fun(int)'
void fun(char *a)
{
cout<<"non-const fun() called";
}
void fun(const char *a)
{
cout<<"const fun() called";
}
int main()
{
const char *ptr = "GeeksforGeeks";
fun(ptr);
return 0;
}
Output: const fun() called
Why is the second one allowed in C++?
The first one's parameters are top-level const. This means that the function can't change the parameter's value, however, the caller doesn't care: The callee gets a copy of the argument, so if a parameter has top-level const, it's an implementation detail. Note that the following works:
void f(int); // forward declare
void g(){ f(42); }
void f(int const i){ /*...*/ } // define above declared function
For the second set of overloads, the const isn't top-level anymore. It describes whether or not the callee can change what the pointer points at. As a caller, you do care about that. It's not just an implementation detail anymore.
First, explain why the first code is not allowed while the second one is ok.
const int and int as parameter, you pass any related type, double, int or anything else can convert to int, both const int and int can accept the pass-in value, there's no difference practically. And if the complier allow to the define both, then which one to call? You don't know, neither the complier. So the first part of code is not allowed.
When it comes to second example, reference and pointer makes a difference. Because you can't pass a const int* to initialize int * and neither can use const int to initialize int&. So if you define two functions with same return type, one is "const version" pointer or reference parameter, and the other is not, that makes a difference. Another question comes up, what if I pass a int object(or called variable, same meaning) or int * pointer, then which one is matched (when parameters are pointer or reference)? The answer is the "non-const" one. if you want to match the "const version" with non-const object or non point to const pointer, you may need const_cast which I am trying to figure out.
So back to your question:
But what if one function has a const argument, another has non-const argument of same type? Will it work for references and pointers?
Yes, it to some extent only works for reference and pointers.
And
If C++ provides it, why does it provide?
Can't tell. I don't have much experience.
For further information, read the very related part sections of C++ Primer 5th.
Links of screenshots are listed as follows:
https://imgur.com/tnqrxVY
https://imgur.com/hF1MjUH
https://imgur.com/Fg2zeEw
By the way, though I am a newbie. But what is int const i from the first answer? And I don't understand what "it's an implementation detail" exactly mean. No offense, just can't understand that part of answer. :D