How to read the function pointer? - c++

How to interpret the following c++ declaration?
int (*(*x[2])())[3];
This is from the example present at Type-cppreference.

The interpretation of the sample declaration in the question is present in the Type-cppreference page linked.
int (*(*x[2])())[3]; // declaration of an array of 2 pointers to functions
// returning pointer to array of 3 int
So the actual question is not about that case in particular; but about how any C++ declaration shall be read.
You can infer all those details starting at the declared name x and moving clockwise respecting parenthesis. You will get to the description above:
x is a an array of dimension 2 of pointers to functions that return a pointer to an array of dimension 3 of ints.
Better explained here as the Clockwise/Spiral Rule: http://c-faq.com/decl/spiral.anderson.html

It is an array of two pointers to functions that return pointer to array of type int[3] and do not have parameters.
Here is a demonstrative program
int ( *f() )[3] { return new int[2][3]; }
int ( *g() )[3] { return new int[4][3]; }
int main()
{
int (*(*x[2])())[3] = { f, g };
for ( auto func : x ) delete []func();
return 0;
}

Related

how to read this declaration int (*(*f2)(int n))[3];

I got this declaration from https://en.cppreference.com/w/cpp/language/scope, but don't know how to parse this declaration even there is a comment below.
my questions is
how to parse the declaration statement (I see it as a function pointer to a function protocol like "int[3] foo(int n)" or "int foo(int n)[3] --- they are illegal in C++ )? Then, how can I construct a concrete function which can be assigned to this function pointer? Thanks.
const int n = 3;
int (*(*f2)(int n))[n]; // OK: the scope of the function parameter 'n'
// ends at the end of its function declarator
// in the array declarator, global n is in scope
// (this declares a pointer to function returning a pointer to an array of 3 int
It's a pointer to a function taking an int and returning a pointer to an int array of size three.
All the comment is saying is that there are two n identifiers in play here. The [n] (in array declarator) is using the const int 3, not the parameter to the function (which is in the function declarator).
Starting in the middle, with each segment being included in the subsequent bullet point as ...:
f2 is a pointer, (*f2).
It's a pointer to a function taking an integer, ...(int).
It returns a pointer to an int array of size three, int (*...)[3].
You can form a concrete function for it as per the following complete program, which output the first element, 42:
#include <iostream>
const int n = 3;
int (*(*f2)(int n))[n];
int (*g2(int))[n] {
static int x[::n] = { 42 }; // Use outer n, not the parameter.
return &x; // since C++ has no VLAs. This
// means parameter is not actually
// needed in this test case, though
// it may be in more complicated
// tests.
}
int main() {
f2 = &g2; // Assign concrete function to pointer.
auto y = f2(3); // Call via pointer, get array.
std::cout << *(y[0]) << '\n'; // Deref first element to get 42.
}
Having said that, I would be rather curious if one of my colleagues submitting something like that for a code review, at least without a large comment explaining it. Although seasoned developers may be able to work it out, those less experienced may have trouble.
And, in fact, even seasoned developers shouldn't have to work it out, especially given it took me a few minutes.
C++ has a very expressive type system which can easily build something like this up in parts, so you don't have to experience migraines trying to work it out. For something like this, I'd be using std::vector (or std::array) unless there was a compelling case for the added complexity caused by more basic types.
You can create a type for pointer to an array of 3 int
typedef int (*array_with_size_n)[n];
and then use it as return type
const int n = 3;
int (*(*f2)(int n))[n];
int arr[n];
array_with_size_n func(int n)
{
return &arr;
}
int main()
{
f2 = &func;
return 0;
}

C++ pointers objects difference

Can somebody explain me the difference between the following?
Those two
float *pointer[10];
float *(pointer[10]);
and those two
int(*pointer_function)();
int *pointer_function();
These two declarations
float *pointer[10];
float *(pointer[10]);
are equivalent. You can write even the following way
float *( ( pointer )[10] );
That is it is a declaration of an array of 10 pointers to float.
These declarations
int(*pointer_function)();
int *pointer_function();
are different. The first one declares a pointer to a function of type int(). The second one declares a function (not a pointer to a function) with type int *().
Here is a demonstrative program
#include <iostream>
int * pointer_function() // #1
{
static int x = 1'000'000;
return &x;
};
int f1() // #2
{
return 2'000'000;
}
int main()
{
std::cout << *pointer_function() /* calling #1 */<< '\n';
int( *pointer_function )() = f1;
std::cout << pointer_function() /* calling #2 */ << '\n';
return 0;
}
Its output is
1000000
2000000
To make more obvious the difference between the declarations you can rewrite the second declaration (that is the declaration of function) the following way
int * ( pointer_function )();
Compare it with the pointer to function declaration
int ( *pointer_function )();
Take into account that a declarator may be enclosed in parentheses.
Always keep in mind the place of Parentheses. Parentheses do not alter the type of the object, but they can alter the binding of complex declarators.
From above code snippet:
float *pointer[10];// Array of 10 pointer to float
float *(pointer[10]); //bracket around array of 10 pointer to float, So same as above
int(*pointer_function)(); // function pointer to achieve callbacks
int * pointer_function(); // function to integer pointer

I am getting errors while trying to return an array in C++

I am getting 3 errors:
line 12:-invalid conversion from int* to int
line 17:-x was not declared in this scope
line 16:- expected primary expression before',' token
Please help me to fix this. Here is the code:
#include<iostream>
int power(int x[5])
{
x[0]=12;
x[1]=23;
x[2]=234;
x[3]=344;
x[4]=232;
return x;
}
int main()
{
int action[5]={1,2,3,,4,5};
std::cout<<x[0]<<std::endl;
x();
std::cout<<x[0]<<std::endl;
return 0;
}
your help would be appreciated!
First of all, the errors are pretty self explanatory.
invalid conversion from int* to int
Your function is declared in such a way it is expected to return an int. Not an array of ints, just an int. Furthermore, you cannot return an array from a function. You can, however, return a pointer to the first element, which in your case is unnecessary.
Guessing that you want your function to simply set values in an array, you can achieve that by declaring the function as void returning:
void power(int x[5])
{
x[0]=12;
x[1]=23;
x[2]=234;
x[3]=344;
x[4]=232;
}
x was not declared in this scope
Well, given your main:
int main()
{
int action[5]={1,2,3,,4,5};
std::cout<<x[0]<<std::endl;
// ^
...
}
Here you attempt to use a variable x, which was never declared inside main or as global variable, thus the compiler has no idea what you are referring to. Simply aliasing an argument as x in some unrelated function won't make it visible to all the code. Your can't use it like this.
expected primary expression before',' token
Take a close look at your main function and at action declaration. The part:
int action[5]={1,2,3,,4,5};
// ^^
is illegal. Notice the ,,. You either should put an integer inbetween them, or delete one of them.
What you probably wanted to achieve, was to first declare the array, print out the first element, apply the power() function and print the first element again, hoping it to change. Given the declaration of power() that I have written, you could achieve it by doing it like so:
#include <iostream>
void power(int x[5])
{
x[0]=12;
x[1]=23;
x[2]=234;
x[3]=344;
x[4]=232;
}
int main()
{
int x[5] = {1,2,3,4,5};
std::cout << x[0] << ' ';
power(x);
std::cout << x[0] << std::endl;
}
That outputs: 1 12.
The first error is a simple mis-declaration: The function receives a pointer and returns a pointer, so the return type is int *, not simply int. By the way, I like it that the function returns the pointer because it allows for function nesting like in the code below (the result of a function call can be the direct argument for another).
Note that the parameter x you declare is a pointer, despite appearances. One can declare a pointer parameter in two ways:
f ( int *p );
or
f2( int p[] );
The two are completely identical; it is impossible to pass arrays to functions. They always are "adjusted" to pointers to the first element.
In fact, one could even write
f2( int p[100] );
which I demonstrate in the code below. The number is irrelevant and ignored. In particular, the compiler does not think there is an array, and it does no type or index checking of the actual arguments.
Now the original function you present is unsafe; it's entirely up to the caller to provide an array with 5 elements.
C++ has the possibility to pass references, and even true references to arrays. Arrays of different sizes have different types, even if the elements are of the same type. This makes normal functions taking references to arrays pretty useless (unless you have an application like a screen buffer where all arrays are of the same size, known at coding time).
But C++ has also templates, which are a facility to construct functions at compile time from a provided pattern, depending on type and int parameters provided by the caller at compile time (but not necessarily at template coding time!). For functions these template parameters can be inferred by the compiler from the function arguments which makes template functions handy to use: The compiler creates the proper one almost magically.
A function iterating over all elements of a fixed-size array is a prime candidate for a template. Check out the last function in the code below.
#include<iostream>
using namespace std; // for brevity in the example
/** An unsafe function based on passing pointers
without element counts.
*/
int *power_5_elems(int x[100]) {
// This is somewhat scary.
// There is no way to check whether the array
// starting at x has indeed 5 elements. It's
// like writing assembler: All is up to the caller.
// Another thing: It would be nice to use a loop.
// We know there are 5 elements, right?
x[0] = x[0] * x[0];
x[1] = x[1] * x[1];
x[2] = x[2] * x[2];
x[3] = x[3] * x[3];
x[4] = x[4] * x[4];
return x;
}
// A reference to an int array with 5 elements.
// Remember, a typedef is written like a variable declaration; the
// type name takes the syntactic place of the variable.
// To decipher it, solve the expression in the parentheses first:
// "I must first de-reference the variable".
// The next operator is the square brackets index operator:
// "I must index the result of the dereferencing" (i.e. it is an array).
// There are 5 indices (0..4).
// The last information is: "The resulting type is int."
// Summed up: This is a reference to an array with 5 elements of type int.
typedef int(&intArr5)[5];
/** This is a nicer way to declare the function below. */
intArr5 power_ref5Arr(intArr5 arrRef);
/** A safe function with very limited usability.
It works only for int arrays with 5 elements.
This is the raw declaration of the same function.
*/
int (&power_ref5Arr( int (&x)[5] ))[5] {
// This is not scary at all.
// Only arrays with 5 ints can be supplied.
for (int i = 0; i < 5; i++)
{
x[i] = x[i] * x[i];
}
return x;
}
/** A versatile function which squares arrays
of arbitrary length of any type that isn't on
a tree on the count of three. It's very similar to the
function above with 5 int elements.
*/
template<int N, typename T>
T(&refPower( T (&arr)[N] ))[N]
{
// Note the use of the template parameter N
// in place of the "5" above.
for (int i = 0; i < N; i++)
{
arr[i] = arr[i] * arr[i];
}
return arr;
}
int main() {
int x[5] = { 2,3,4,5,6 };
int *p = &x[0]; // make clear: this is a pointer
power_5_elems(power_5_elems(power_5_elems(x)));
cout << x[0] << endl;
// The function actually expects a pointer!
// The pointer points to x.
power_5_elems(p);
cout << x[0] << endl;
int y[2] = { 2,3 };
refPower(refPower(refPower(y)));
cout << y[0] << endl;
double z[2] = { 0.2 , 0.3 };
refPower(refPower(refPower(z)));
cout << z[0] << endl;
return 0;
}

What do each of these arrays mean in C++?

I received lecture slides for C++ that merely mention these without explaining what they mean and what are their differences:
int (*arr)[]={...};
int *(arr[])={...};
int (&arr)[]={...};
int &(arr[])={...}; // not allowed?
What do each of these mean? I tried running a program with some of these, but I'm getting errors because I don't know what to put in the initialization list.
int (*arr)[] = { ... };
This is not an array at all. This is a pointer to an array of unknown size. Note that this a scalar type. It is just a data pointer, no different in nature from any other data pointer. Which means that the only way to use { ... } initializer with it is to specify a single value of proper type inside the { ... }. E.g.
int (*arr)[] = { nullptr };
which is the same as
int (*arr)[] = nullptr;
int *(arr[]) = { ... };
This is indeed an array. The same thing can be expressed as
int *arr[] = { ... };
This is an array of int * pointers. It size will depend on how many initializers are supplied in { ... }. E.g.
int *arr[] = { nullptr, &some_int, &some_other_int };
declares arr as an array of 3 pointers of type int *.
int (&arr)[] = { ... };
This is not an array per se. This is a reference to an array of unknown size. Again, the only legal { ... } initializer in this case would be just one lvalue of type int [] inside the { ... }. If the array was declared const, you'd be able to attach it to a temporary array of ints using this syntax, e.g.
const int (&arr)[] = { 1, 2, 3 };
But without const it is not possible. (I have my doubts about the legality of this even with const though. GCC accepts it.)
int &(arr[]) = { ... };
This is an attempt to declare an array of references. Not allowed.
You need to use the Clockwise/Spiral Rule.
int (*arr)[]={...}; // pointer to array of int
int *(arr[])={...}; // array of int pointers
int (&arr)[]={...}; // a reference to an array of int
int &(arr[])={...}; // an array of int references
The last one though is illegal: Why arrays of references are illegal?

How do you make a function "size-aware" of its parameters?

From here: https://stackoverflow.com/a/3473454/499125
int ( &fillarr( int (&arr)[5] ) )[5] { // no decay; argument must be size 5
return arr;
}
The definition above can force the compiler to become size-aware of its parameters. This statement seems complex to me. Can someone give an anatomy of this statement or explain how does the statement achieves the size-awareness?
Can this be extended to handle multiple parameters?
It all boils down to being able to read the declaration. A simpler way of writing exactly the same would be:
typedef int int5[5]; // create a typedef
int5& fillarr( int5& ) {
}
As of the exact way of reading the original declaration, just break it into pieces:
int (&fillarr( int (&arr)[5] ))[ 5 ];
^^^^^^^^^^^^^ // A: reference to array of 5 int
^^^^^^ ^^^^^^ // B: reference to array of 5 int
^^^^^^^^ ^ // C: function taking A and returning B
You can split understanding this in two parts, 1) the return value and 2) the parameter type:
int ( &fillarr() )[5] {
static int arr[5];
return arr;
}
We can have a look at the type: int (&fillarr())[5]. To understand this, unfortunately the old C rule: "Declaration is like usage in expressions" doesn't work with references, so let's have a look at a similar declaration instead:
int (*fillarr())[5];
This is a function that returns a pointer instead of a reference to an array of size 5. How do I figure? Well, assume we do have a function f that returns a pointer to an array of ints, how would we access the fifth element? Let's see, we first have to call the function: f(). Then we have to dereference the result *f() and then access the fifth element (which doesn't exist, but ignore that) (*f())[5] which is an int. This is exactly the declaration syntax:
int x;
int (*f())[5];
x = (*f())[5];
// ^^^-------- call f -> yields pointer to array of 5 ints
// ^----------- dereferene the result of f -> yields array of 5 ints
// ^^^---- access the fifth element
Now you only substitute the * for an & because you're returning a reference in your example.
The parameter syntax works analogously.