Here's the code:
#include<iostream>
using namespace std;
typedef struct ptrs
{
int (*addptr)(int a, int b);
}mems;
int add(int a, int b)
{
int result = a+b;
return result;
}
int main()
{
mems ptrtest;
ptrtest.addptr = &add;
int c = (*ptrtest.addptr)(3,4);
//int c = ptrtest.addptr(3,4);
cout << c << endl;
return 0;
}
if I replace the code int c = (*ptrtest.addptr)(3,4); with it's next line(annotated now), the result will be the same, why is that?
Of course, int c = (*ptrtest.addptr)(3,4); is the base case. However, in C++ (and in C as well), if you use the call (()) operator on a function pointer, it will do the "dereferencing" automatically. Just like when assigned to a variable of function pointer type, the name of a function decays into a function pointer, i. e.
int (*fptr)() = some_func;
is just as valid as
int (*fptr)() = &some_func;
albeit the type of func is int ()(void).
Functions and function pointers can be used interchangeably, presumably for convenience. In particular, section 5.2.2 of the C++11 standard specifies that a function call can occur using a function or a pointer to a function.
C++ will automatically cast a function name to a function pointer (and vise versa) if doing so will create correct syntax.
Related
As a C++ learner, I came across the following piece of code from C++ Language Tutorial and got two questions, could any expert provide some guidance on those?
#include <iostream>
using namespace std;
int addition (int a, int b)
{ return (a+b); }
int subtraction (int a, int b)
{ return (a-b); }
int operation (int x, int y, int
(*functocall)(int,int))
{
int g;
g = (*functocall)(x,y);
return (g);
}
int main () {
int m,n;
int (*minus)(int,int) = subtraction;
m = operation (7, 5, addition);
n = operation (20, m, minus);
cout <<n;
return 0;
}
In function "operation" definition:
Question 1: for "g = (*functocall)(x,y)", does it deference the pointer that points to a function (ex.subtraction) and assign it to g?
Question 2: for "return(g)", I'm wondering why we put parenthesis for g?
And for "int (*minus)(int,int) = subtraction;" in the main function, is that okay if we write the following instead?
int (*minus)(int,int)
minus = subtraction
Question 1: for g = (*functocall)(x,y), does it deference the
pointer that points to a function (ex.subtraction) and assign it to g?
Answer: No.
(*functocall)(x,y);
is simply one allowable syntax for invoking the function from the pointer passed as a parameter. It is entirely equivalent to:
functocall(x,y);
Which simply eliminates the (*...) syntax which is allowable but unnecessary.
Question 2: for return(g), I'm wondering why we put parenthesis for
g?
The parenthesis too are discretionary and are superfluous to the return. Simply providing:
return g;
is all that is needed as there is no expression requiring evaluation priority provided by the enclosing (..).
Before I start, your code uses way more parenthesis than it needs.
Here is the same code, better formatted and reduced:
#include <iostream>
using namespace std;
int addition (int a, int b)
{ return a+b; }
int subtraction (int a, int b)
{ return a-b; }
int operation (int x, int y, int (*functocall)(int,int))
{
int g;
g = functocall(x,y);
return g;
}
int main () {
int m,n;
int (*minus)(int,int) = subtraction;
m = operation (7, 5, addition);
n = operation (20, m, minus);
cout <<n<<"\n";
return 0;
}
for "g = (*functocall)(x,y)", does it deference the pointer that points to a function (ex.subtraction) and assign it to g?
In a nutshell - yes. When calling a function through it's pointer, it is not necessary to explicitly dereference it. I know, it's surprising and counter to the way pointers are typically used.
Think of it this way. Whenever you are just writing the name of a function, you are essentially getting the function's pointer. This is why you wrote as you did, rather than write:
m = operation (7, 5, &addition);
You do not need to explicitly dereference when using a function pointer for the same reason you do not need to explicitly use the address of operator when taking its address in the first place.
Question 2: for "return(g)", I'm wondering why we put parenthesis for g?
There is positively no good reason to. In fact, there is no reason to do it for any of your return statements.
And for "int (*minus)(int,int) = subtraction;" in the main function,
is that okay if we write the following instead?
int (*minus)(int,int);
minus = subtraction;
Personally, I recommend you use:
int (*minus)(int,int) = nullptr;
minus = subtraction;
so as not to leave uninitialized variables, but otherwise, yes, absolutely. A pointer to function variable is just like any other variable.
For example, in a function, "a" array and "first" array (normally arrays cannot take an integer as a parameter which is not const) can take "d" and "a1" as parameter). My question is that why this works like that, what is the difference between them?
#include <iostream>
using namespace std;
class BC {
int first[];
int modify(int a[], int d) {
int a1;
a[a1];
first[a1];
int sec[a1];
//a[d];
//first[d];
//sec[d];
}
};
a[a1]; // This is not an array declaration. This is referring to the a1-th element of the array.
first[a1]; // Same as above
int sec[a1]; // This IS a declaration and so SHOULD fail because a1 is non-const.
To further illuminate, you could say
a[a1] = 5;
or
int x = a[a1];
When you write
a[a1];
you are referring to an element of an array, but without doing anything with the value. This is allowed even though it seems pointless. Potentially, the [] operator can be overidden and hence this statement COULD do something. That's why it's allowed.
I am very confused with c++ pointers and reference operators. My main confusion is the following (simple ) code:
#include <iostream>
using namespace std;
void changeInt(int &a)
{
a *= 3;
}
int main()
{
int n = 3;
changeInt(n);
cout << n << endl;
return 0;
}
Mainly, I am confused as to why changing the address (&a) changes the actual variable (n). When I first attempted this problem this was my code:
#include <iostream>
using namespace std;
void changeInt(int &a)
{
*a *= 3;
}
int main()
{
int n = 3;
changeInt(n);
cout << n << endl;
return 0;
}
But this gives me an error. Why is it that when I change the address it changes the variable, but when I change the value pointed by the address I get an error?
Your second example is not valid C++, you can only dereference a pointer (or an object whose type overload operator*, which is not your case).
Your first example pass the parameter by reference (int &a is not "the address of a", it is a reference to a), which is why a change to a really is a change to the object being passed by the function (in you case, n)
The ampersand (&) in that context means a reference, not the "address". E.g.:
int some_int;
int & a = some_int; // Declare 'a', a reference to 'some_int'
int * p = &some_int; // '&' in this context is "the address of" 'some_int'
A reference is equivalent to a pointer in many ways, but it behaves like a value type.
See this thread and the wikipedia entry to learn more.
The ampersand indicates that a variable is passed by reference to your function -- but inside the function the variable is treated as if it were passed by value. This is syntactic sugar, to make writing code that accepts references simpler to understand.
I have a class assignment that says:
Write a declaration for a function that takes two int parameters and returns an int, and declare a vector whose elements have this function pointer type.
Since the function and vector are both int is this correct? I'm really fuzzy on pointers still. This is what I have:
#include <iostream>
#include <vector>
using std::cin; using std::cout; using std::endl; using std::vector;
// This is my function that take two ints and returns and int
int AddFunc ( int a, int b) { int addResult; addResult = a + b; return (addResult);}
int main()
{
vector <int> v1; // Declare a vector whose elements have this functions pointer types
int add1, add2, add3 = 0;
cout << "Enter two numbers to be added with my AddFunc function: ";
cin >> add1 >> add2;
add3 = AddFunc (add1, add2);
cout << "The numbers added equal: " << add3 << endl;
v1.push_back(add3);
cout << "The first element in the vector v1 is: " << v1 [0] << endl;
return 0;
}
The function pointer type is int (*)(int, int). You want this:
typedef int (*fptr)(int, int);
std::vector<fptr> v;
Example:
int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
v.push_back(&add);
v.push_back(&mul);
And then something like this:
for (f : v) { std::cout << "f(5, 7) = " << f(5, 7) << std::endl; }
In C++ you have the abilty to define a function pointer, like so:
int (*pfunc) (int, int);
This is a variable, to which you can assign the address of a function, as long as it has the specified signature, like so:
pfunc = AddFunc; // Assign the adress of a function
pfunc(1,2) // Now call the function through the pointer
Now, note that pfunc is the variable name, and its "official" type is int (*) (int,int)
Naturally, this can all get very confusing, so you'd probably wanna typedef it:
typedef int (*AdderFunc)(int, int);
AdderFunc pfunc = AddFunc;
pfunc(1,2);
The assignment wants a vector of function pointers for your function. Function pointers are a bit difficult to read if you're not used to them. Here's a method you can use to write a function pointer type.
First, write the argument list of the function. AddFunc() takes two int arguments, so at first you have:
(int, int)
For this to be a function pointer, you prefix it with (*):
(*)(int, int)
Lastly, you prefix the whole thing with the return type of the function. In this case, int:
int (*)(int, int)
You can use that as-is as the type of your vector:
std::vector<int (*)(int, int)> v;
This will work. However, it's usually more clear to actually define your own type for the function pointer (using typedef). At first, it seems tricky to do so, but it's easy. You already wrote down the type using the above method. The only thing that's missing is to give it a name. You do that by writing the name after the * in (*). For example (*func_ptr), so you have:
int (*func_ptr)(int, int)
And that's all you need for a typedef:
typedef int (*func_ptr)(int, int);
Now whenever you need that particular function pointer type, instead of:
int (*)(int, int)
you can write:
func_ptr
instead. So your vector declaration becomes:
std::vector<func_ptr> v;
As far as vector is concerned, func_ptr is a pointer type just like any other.
Function pointers differ from "regular" pointers in that "dereferencing" them means calling the function they point to. You don't actually dereference a function pointer. Instead, you use the () operator on them. Doing that calls the function they point to.
Assigning to a function pointer means assigning it the address of a function. For example, if you have a variable of type func_ptr (which you typedefed above):
func_ptr AddFunc_p;
You can assign it the address of AddFunc() with:
AddFunc_p = AddFunc;
Note the missing parentheses in AddFunc. You only write the name of the function, since you don't want to actually call that function, but rather want its address so you can assign it to AddFunc_p. Now you can call AddFunc() through AddFunc_p with:
AddFunc_p(some_int, another_int);
You should now be able to deduct how to put function pointers in a vector and how to apply the () operator on its elements. It will help to keep in mind that the vector simply contains elements of type func_ptr.
If I have a function that takes int *&, what does it means? How can I pass just an int or a pointer int to that function?
function(int *& mynumber);
Whenever I try to pass a pointer to that function it says:
error: no matching function for call to 'function(int *)'
note: candidate is 'function(int *&)'
It's a reference to a pointer to an int. This means the function in question can modify the pointer as well as the int itself.
You can just pass a pointer in, the one complication being that the pointer needs to be an l-value, not just an r-value, so for example
int myint;
function(&myint);
alone isn't sufficient and neither would 0/NULL be allowable, Where as:
int myint;
int *myintptr = &myint;
function(myintptr);
would be acceptable. When the function returns it's quite possible that myintptr would no longer point to what it was initially pointing to.
int *myintptr = NULL;
function(myintptr);
might also make sense if the function was expecting to allocate the memory when given a NULL pointer. Check the documentation provided with the function (or read the source!) to see how the pointer is expected to be used.
Simply: a reference to a pointer.
In C, without references, the traditional way to "relocate" a pointer, is to pass a pointer to a pointer:
void c_find(int** p, int val); /* *p will point to the node with value 'val' */
In C++, this can be expressed by the reference syntax, to avoid the awkward double dereference.
void cpp_find(int*& p, int val); // p will point to the node with value 'val'
It means a reference to a pointer to an int. In other words, the function can change the parameter to point to something else.
To pass a variable in, just pass an int*. As awoodland points out, what's passed in must be an l-value.
Edit:
To build on awoodland's example:
#include <iostream>
void foo(int*& var)
{
delete var;
var = new int;
}
int main(int argc, char* argv[])
{
int* var = NULL;
std::cout << var << std::endl;
foo(var); // this function can/will change the value of the pointer
std::cout << var << std::endl;
delete var;
return 0;
}
function takes a single parameter, mynumber which is a reference to a pointer to an int.
This is useful when you need to pass a pointer to a function, and that function might change the pointer. For example, if you function is implemented like this:
function(int*& mynumber)
{
if( !mynumber )
mynumber = new int;
*mynumber = 42;
}
...Then something like this might happen in the calling code:
int main()
{
int* mynumber = 0;
function(mynumber); // function will change what "mynumber" points to
cout << *mynumber;
return 0;
}
This is a reference to a pointer to int - you would have to pass in the address of an int to this function, and be aware that the function could change the pointer through the reference.
Dumb example:
void func(int*& iref)
{
iref = new int;
}
int main()
{
int i(0);
int* pi(&i);
func(pi);
// pi no longer equal to &i
return 0;
}