I've recently decided that I just have to finally learn C/C++, and there is one thing I do not really understand about pointers or more precisely, their definition.
How about these examples:
int* test;
int *test;
int * test;
int* test,test2;
int *test,test2;
int * test,test2;
Now, to my understanding, the first three cases are all doing the same: Test is not an int, but a pointer to one.
The second set of examples is a bit more tricky. In case 4, both test and test2 will be pointers to an int, whereas in case 5, only test is a pointer, whereas test2 is a "real" int. What about case 6? Same as case 5?
4, 5, and 6 are the same thing, only test is a pointer. If you want two pointers, you should use:
int *test, *test2;
Or, even better (to make everything clear):
int* test;
int* test2;
White space around asterisks have no significance. All three mean the same thing:
int* test;
int *test;
int * test;
The "int *var1, var2" is an evil syntax that is just meant to confuse people and should be avoided. It expands to:
int *var1;
int var2;
Many coding guidelines recommend that you only declare one variable per line. This avoids any confusion of the sort you had before asking this question. Most C++ programmers I've worked with seem to stick to this.
A bit of an aside I know, but something I found useful is to read declarations backwards.
int* test; // test is a pointer to an int
This starts to work very well, especially when you start declaring const pointers and it gets tricky to know whether it's the pointer that's const, or whether its the thing the pointer is pointing at that is const.
int* const test; // test is a const pointer to an int
int const * test; // test is a pointer to a const int ... but many people write this as
const int * test; // test is a pointer to an int that's const
Use the "Clockwise Spiral Rule" to help parse C/C++ declarations;
There are three simple steps to follow:
Starting with the unknown element, move in a spiral/clockwise
direction; when encountering the following elements replace them with
the corresponding english statements:
[X] or []: Array X size of... or Array undefined size of...
(type1, type2): function passing type1 and type2 returning...
*: pointer(s) to...
Keep doing this in a spiral/clockwise direction until all tokens have been covered.
Always resolve anything in parenthesis first!
Also, declarations should be in separate statements when possible (which is true the vast majority of times).
There are three pieces to this puzzle.
The first piece is that whitespace in C and C++ is normally not significant beyond separating adjacent tokens that are otherwise indistinguishable.
During the preprocessing stage, the source text is broken up into a sequence of tokens - identifiers, punctuators, numeric literals, string literals, etc. That sequence of tokens is later analyzed for syntax and meaning. The tokenizer is "greedy" and will build the longest valid token that's possible. If you write something like
inttest;
the tokenizer only sees two tokens - the identifier inttest followed by the punctuator ;. It doesn't recognize int as a separate keyword at this stage (that happens later in the process). So, for the line to be read as a declaration of an integer named test, we have to use whitespace to separate the identifier tokens:
int test;
The * character is not part of any identifier; it's a separate token (punctuator) on its own. So if you write
int*test;
the compiler sees 4 separate tokens - int, *, test, and ;. Thus, whitespace is not significant in pointer declarations, and all of
int *test;
int* test;
int*test;
int * test;
are interpreted the same way.
The second piece to the puzzle is how declarations actually work in C and C++1. Declarations are broken up into two main pieces - a sequence of declaration specifiers (storage class specifiers, type specifiers, type qualifiers, etc.) followed by a comma-separated list of (possibly initialized) declarators. In the declaration
unsigned long int a[10]={0}, *p=NULL, f(void);
the declaration specifiers are unsigned long int and the declarators are a[10]={0}, *p=NULL, and f(void). The declarator introduces the name of the thing being declared (a, p, and f) along with information about that thing's array-ness, pointer-ness, and function-ness. A declarator may also have an associated initializer.
The type of a is "10-element array of unsigned long int". That type is fully specified by the combination of the declaration specifiers and the declarator, and the initial value is specified with the initializer ={0}. Similarly, the type of p is "pointer to unsigned long int", and again that type is specified by the combination of the declaration specifiers and the declarator, and is initialized to NULL. And the type of f is "function returning unsigned long int" by the same reasoning.
This is key - there is no "pointer-to" type specifier, just like there is no "array-of" type specifier, just like there is no "function-returning" type specifier. We can't declare an array as
int[10] a;
because the operand of the [] operator is a, not int. Similarly, in the declaration
int* p;
the operand of * is p, not int. But because the indirection operator is unary and whitespace is not significant, the compiler won't complain if we write it this way. However, it is always interpreted as int (*p);.
Therefore, if you write
int* p, q;
the operand of * is p, so it will be interpreted as
int (*p), q;
Thus, all of
int *test1, test2;
int* test1, test2;
int * test1, test2;
do the same thing - in all three cases, test1 is the operand of * and thus has type "pointer to int", while test2 has type int.
Declarators can get arbitrarily complex. You can have arrays of pointers:
T *a[N];
you can have pointers to arrays:
T (*a)[N];
you can have functions returning pointers:
T *f(void);
you can have pointers to functions:
T (*f)(void);
you can have arrays of pointers to functions:
T (*a[N])(void);
you can have functions returning pointers to arrays:
T (*f(void))[N];
you can have functions returning pointers to arrays of pointers to functions returning pointers to T:
T *(*(*f(void))[N])(void); // yes, it's eye-stabby. Welcome to C and C++.
and then you have signal:
void (*signal(int, void (*)(int)))(int);
which reads as
signal -- signal
signal( ) -- is a function taking
signal( ) -- unnamed parameter
signal(int ) -- is an int
signal(int, ) -- unnamed parameter
signal(int, (*) ) -- is a pointer to
signal(int, (*)( )) -- a function taking
signal(int, (*)( )) -- unnamed parameter
signal(int, (*)(int)) -- is an int
signal(int, void (*)(int)) -- returning void
(*signal(int, void (*)(int))) -- returning a pointer to
(*signal(int, void (*)(int)))( ) -- a function taking
(*signal(int, void (*)(int)))( ) -- unnamed parameter
(*signal(int, void (*)(int)))(int) -- is an int
void (*signal(int, void (*)(int)))(int); -- returning void
and this just barely scratches the surface of what's possible. But notice that array-ness, pointer-ness, and function-ness are always part of the declarator, not the type specifier.
One thing to watch out for - const can modify both the pointer type and the pointed-to type:
const int *p;
int const *p;
Both of the above declare p as a pointer to a const int object. You can write a new value to p setting it to point to a different object:
const int x = 1;
const int y = 2;
const int *p = &x;
p = &y;
but you cannot write to the pointed-to object:
*p = 3; // constraint violation, the pointed-to object is const
However,
int * const p;
declares p as a const pointer to a non-const int; you can write to the thing p points to
int x = 1;
int y = 2;
int * const p = &x;
*p = 3;
but you can't set p to point to a different object:
p = &y; // constraint violation, p is const
Which brings us to the third piece of the puzzle - why declarations are structured this way.
The intent is that the structure of a declaration should closely mirror the structure of an expression in the code ("declaration mimics use"). For example, let's suppose we have an array of pointers to int named ap, and we want to access the int value pointed to by the i'th element. We would access that value as follows:
printf( "%d", *ap[i] );
The expression *ap[i] has type int; thus, the declaration of ap is written as
int *ap[N]; // ap is an array of pointer to int, fully specified by the combination
// of the type specifier and declarator
The declarator *ap[N] has the same structure as the expression *ap[i]. The operators * and [] behave the same way in a declaration that they do in an expression - [] has higher precedence than unary *, so the operand of * is ap[N] (it's parsed as *(ap[N])).
As another example, suppose we have a pointer to an array of int named pa and we want to access the value of the i'th element. We'd write that as
printf( "%d", (*pa)[i] );
The type of the expression (*pa)[i] is int, so the declaration is written as
int (*pa)[N];
Again, the same rules of precedence and associativity apply. In this case, we don't want to dereference the i'th element of pa, we want to access the i'th element of what pa points to, so we have to explicitly group the * operator with pa.
The *, [] and () operators are all part of the expression in the code, so they are all part of the declarator in the declaration. The declarator tells you how to use the object in an expression. If you have a declaration like int *p;, that tells you that the expression *p in your code will yield an int value. By extension, it tells you that the expression p yields a value of type "pointer to int", or int *.
So, what about things like cast and sizeof expressions, where we use things like (int *) or sizeof (int [10]) or things like that? How do I read something like
void foo( int *, int (*)[10] );
There's no declarator, aren't the * and [] operators modifying the type directly?
Well, no - there is still a declarator, just with an empty identifier (known as an abstract declarator). If we represent an empty identifier with the symbol λ, then we can read those things as (int *λ), sizeof (int λ[10]), and
void foo( int *λ, int (*λ)[10] );
and they behave exactly like any other declaration. int *[10] represents an array of 10 pointers, while int (*)[10] represents a pointer to an array.
And now the opinionated portion of this answer. I am not fond of the C++ convention of declaring simple pointers as
T* p;
and consider it bad practice for the following reasons:
It's not consistent with the syntax;
It introduces confusion (as evidenced by this question, all the duplicates to this question, questions about the meaning of T* p, q;, all the duplicates to those questions, etc.);
It's not internally consistent - declaring an array of pointers as T* a[N] is asymmetrical with use (unless you're in the habit of writing * a[i]);
It cannot be applied to pointer-to-array or pointer-to-function types (unless you create a typedef just so you can apply the T* p convention cleanly, which...no);
The reason for doing so - "it emphasizes the pointer-ness of the object" - is spurious. It cannot be applied to array or function types, and I would think those qualities are just as important to emphasize.
In the end, it just indicates confused thinking about how the two languages' type systems work.
There are good reasons to declare items separately; working around a bad practice (T* p, q;) isn't one of them. If you write your declarators correctly (T *p, q;) you are less likely to cause confusion.
I consider it akin to deliberately writing all your simple for loops as
i = 0;
for( ; i < N; )
{
...
i++;
}
Syntactically valid, but confusing, and the intent is likely to be misinterpreted. However, the T* p; convention is entrenched in the C++ community, and I use it in my own C++ code because consistency across the code base is a good thing, but it makes me itch every time I do it.
I will be using C terminology - the C++ terminology is a little different, but the concepts are largely the same.
As others mentioned, 4, 5, and 6 are the same. Often, people use these examples to make the argument that the * belongs with the variable instead of the type. While it's an issue of style, there is some debate as to whether you should think of and write it this way:
int* x; // "x is a pointer to int"
or this way:
int *x; // "*x is an int"
FWIW I'm in the first camp, but the reason others make the argument for the second form is that it (mostly) solves this particular problem:
int* x,y; // "x is a pointer to int, y is an int"
which is potentially misleading; instead you would write either
int *x,y; // it's a little clearer what is going on here
or if you really want two pointers,
int *x, *y; // two pointers
Personally, I say keep it to one variable per line, then it doesn't matter which style you prefer.
#include <type_traits>
std::add_pointer<int>::type test, test2;
In 4, 5 and 6, test is always a pointer and test2 is not a pointer. White space is (almost) never significant in C++.
The rationale in C is that you declare the variables the way you use them. For example
char *a[100];
says that *a[42] will be a char. And a[42] a char pointer. And thus a is an array of char pointers.
This because the original compiler writers wanted to use the same parser for expressions and declarations. (Not a very sensible reason for a langage design choice)
I would say that the initial convention was to put the star on the pointer name side (right side of the declaration
in the c programming language by Dennis M. Ritchie the stars are on the right side of the declaration.
by looking at the linux source code at https://github.com/torvalds/linux/blob/master/init/main.c
we can see that the star is also on the right side.
You can follow the same rules, but it's not a big deal if you put stars on the type side.
Remember that consistency is important, so always but the star on the same side regardless of which side you have choose.
In my opinion, the answer is BOTH, depending on the situation.
Generally, IMO, it is better to put the asterisk next to the pointer name, rather than the type. Compare e.g.:
int *pointer1, *pointer2; // Fully consistent, two pointers
int* pointer1, pointer2; // Inconsistent -- because only the first one is a pointer, the second one is an int variable
// The second case is unexpected, and thus prone to errors
Why is the second case inconsistent? Because e.g. int x,y; declares two variables of the same type but the type is mentioned only once in the declaration. This creates a precedent and expected behavior. And int* pointer1, pointer2; is inconsistent with that because it declares pointer1 as a pointer, but pointer2 is an integer variable. Clearly prone to errors and, thus, should be avoided (by putting the asterisk next to the pointer name, rather than the type).
However, there are some exceptions where you might not be able to put the asterisk next to an object name (and where it matters where you put it) without getting undesired outcome — for example:
MyClass *volatile MyObjName
void test (const char *const p) // const value pointed to by a const pointer
Finally, in some cases, it might be arguably clearer to put the asterisk next to the type name, e.g.:
void* ClassName::getItemPtr () {return &item;} // Clear at first sight
The pointer is a modifier to the type. It's best to read them right to left in order to better understand how the asterisk modifies the type. 'int *' can be read as "pointer to int'. In multiple declarations you must specify that each variable is a pointer or it will be created as a standard variable.
1,2 and 3) Test is of type (int *). Whitespace doesn't matter.
4,5 and 6) Test is of type (int *). Test2 is of type int. Again whitespace is inconsequential.
I have always preferred to declare pointers like this:
int* i;
I read this to say "i is of type int-pointer". You can get away with this interpretation if you only declare one variable per declaration.
It is an uncomfortable truth, however, that this reading is wrong. The C Programming Language, 2nd Ed. (p. 94) explains the opposite paradigm, which is the one used in the C standards:
The declaration of the pointer ip,
int *ip;
is intended as a mnemonic; it says that the expression *ip is an
int. The syntax of the declaration for a variable mimics the syntax
of expressions in which the variable might appear. This reasoning
applies to function declarations as well. For example,
double *dp, atof(char *);
says that in an expression *dp and atof(s) have values of type
double, and that the argument of atof is a pointer to char.
So, by the reasoning of the C language, when you declare
int* test, test2;
you are not declaring two variables of type int*, you are introducing two expressions that evaluate to an int type, with no attachment to the allocation of an int in memory.
A compiler is perfectly happy to accept the following:
int *ip, i;
i = *ip;
because in the C paradigm, the compiler is only expected to keep track of the type of *ip and i. The programmer is expected to keep track of the meaning of *ip and i. In this case, ip is uninitialized, so it is the programmer's responsibility to point it at something meaningful before dereferencing it.
A good rule of thumb, a lot of people seem to grasp these concepts by: In C++ a lot of semantic meaning is derived by the left-binding of keywords or identifiers.
Take for example:
int const bla;
The const applies to the "int" word. The same is with pointers' asterisks, they apply to the keyword left of them. And the actual variable name? Yup, that's declared by what's left of it.
Related
Here is the way I understand * and & symbols in C and C++.
In C, * serves two purposes. First it can be used to declare a pointer variable like so int* pointerVariable
It can however be used as a dereference operator like so *pointerVariable which returns value saved at that address, it understands how to interpret bytes at that address based on what data type we have declared that pointer is pointing to. In our case int* therefore it reads bytes saved at that address and returns back whole number.
We also have address-of operator in C like so &someVariable which returns address of bytes saved underneath someVariable name.
However in C++ (not in C), we also get a possibility to use & in declaration of reference like so int& someReference. This will turn variable someReference into a reference, which means that whatever value we pass into that variable, it will automatically get address of the value we are passing into it and it will hold it.
Do I get this correctly?
Do I get this correctly?
Yes, but it is better to think about pointers and references in terms of what you want to do.
References are very useful for all those cases where you need to refer to some object without copying it. References are simple: they are always valid and there is no change in syntax when you use the object.
Pointers are for the rest of cases. Pointers allow you to work with addresses (pointer arithmetic), require explicit syntax to refer to the object behind them (*, &, -> operators), are nullable (NULL, nullptr), can be modified, etc.
In summary, references are simpler and easier to reason about. Use pointers when a reference does not cut it.
General Syntax for defining a pointer:
data-type * pointer-name = &variable-name
The data-type of the pointer must be the same as that of the variable to which it is pointing.
void type pointer can handle all data-types.
General Syntax for defining a reference variable:
data-type & reference-name = variable-name
The data-type of the reference variable must be the same as that of the variable of which it is an alias.
Let's look at each one of them, for the purpose of explanation, I will go with a simple Swap Program both in C and C++.
Swapping two variables by the pass by reference in C
#include <stdio.h>
void swap(int *,int *); //Function prototype
int main()
{
int a = 10;
int b = 20;
printf("Before Swap: a=%d, b=%d\n",a,b);
swap(&a,&b); //Value of a,b are passed by reference
printf("After Swap: a=%d, b=%d\n",a,b);
return 0;
}
void swap(int *ptra,int *ptrb)
{
int temp = *ptra;
*ptra = *ptrb;
*ptrb = temp;
}
In the code above we have declared and initialized variable a and
b to 10 and 20 respectively.
We then pass the address of a
and b to swap function by using the addressof (&) operator. This operator gives the address of the variable.
These passed arguments are assigned to the respective formal parameters which in this case are int pointers ptra and ptrb.
To swap the variables, we first need to temporarily store the value of one of the variables. For this, we stored value pointed by the pointer ptra to a variable temp. This was done by first dereferencing the pointer by using dereference (*) operator and then assigning it to temp. dereference (*) operator is used to access the value stored in the memory location pointed to by a pointer.
Once, the value of pointed by ptra is saved, we can then assign it a new value, which in this case, we assigned it the value of variable b(again with the help of dereference (*) operator). And the ptrb was assigned the value saved in temp(original value of a). Therefore, swapping the value of a and b, by altering the memory location of those variables.
Note: We can use dereference (*) operator and the addressof (&) operator together like this, *&a, they nullify each other resulting in just a
We can write a similar program in C++ by using pointers to swap two numbers as well but the language supports another type variable known as the reference variable. It provides an alias (alternative name) for a previously defined variable.
Swapping two variables by the call by reference in C++
#include <iostream>
using namespace std;
void swap(int &,int &); //Function prototype
int main()
{
int a = 10;
int b = 20;
cout << "Before Swap: a= " << a << " b= " << b << endl;
swap(a,b);
cout << "After Swap: a= " << a << " b= " << b << endl;
return 0;
}
void swap(int &refa,int &refb)
{
int temp = refa;
refa = refb;
refb = temp;
}
In the code above when we passed the variables a and b to the function swap, what happened is the variable a and b got their respective reference variables refa and refb inside the swap. It's like giving a variable another alias name.
Now, we can directly swap the variables without the dereferencing (*) operator using the reference variables.
Rest logic remains the same.
So before we get into the differences between pointers and references, I feel like we need to talk a little bit about declaration syntax, partly to explain why pointer and reference declarations are written that way and partly because the way many C++ programmers write pointer and reference declarations misrepresent that syntax (get comfortable, this is going to take a while).
In both C and C++, declarations are composed of a sequence of declaration specifiers followed by a sequence of declarators1. In a declaration like
static unsigned long int a[10], *p, f(void);
the declaration specifiers are static unsigned long int and the declarators are a[10], *p, and f(void).
Array-ness, pointer-ness, function-ness, and in C++ reference-ness are all specified as part of the declarator, not the declaration specifiers. This means when you write something like
int* p;
it’s parsed as
int (*p);
Since the unary * operator is a unique token, the compiler doesn't need whitespace to distinguish it from the int type specifier or the p identifier. You can write it as int *p;, int* p;, int * p;, or even int*p;
It also means that in a declaration like
int* p, q;
only p is declared as a pointer - q is a regular int.
The idea is that the declaration of a variable closely matches its use in the code ("declaration mimics use"). If you have a pointer to int named p and you want to access the pointed-to value, you use the * operator to dereference it:
printf( "%d\n", *p );
The expression *p has type int, so the declaration of p is written
int *p;
This tells us that the variable p has type "pointer to int" because the combination of p and the unary operator * give us an expression of type int. Most C programmers will write the pointer declaration as shown above, with the * visibly grouped with p.
Now, Bjarne and the couple of generations of C++ programmers who followed thought it was more important to emphasize the pointer-ness of p rather than the int-ness of *p, so they introduced the
int* p;
convention. However, this convention falls down for anything but a simple pointer (or pointer to pointer). It doesn't work for pointers to arrays:
int (*a)[N];
or pointers to functions
int (*f)(void);
or arrays of pointers to functions
int (*p[N])(void);
etc. Declaring an array of pointers as
int* a[N];
just indicates confused thinking. Since [] and () are postfix, you cannot associate the array-ness or function-ness with the declaration specifiers by writing
int[N] a;
int(void) f;
like you can with the unary * operator, but the unary * operator is bound to the declarator in exactly the same way as the [] and () operators are.2
C++ references break the rule about "declaration mimics use" hard. In a non-declaration statement, an expression &x always yields a pointer type. If x has type int, &x has type int *. So & has a completely different meaning in a declaration than in an expression.
So that's syntax, let's talk about pointers vs. references.
A pointer is just an address value (although with additional type information). You can do (some) arithmetic on pointers, you can initialize them to arbitrary values (or NULL), you can apply the [] subscript operator to them as though they were an array (indeed, the array subscript operation is defined in terms of pointer operations). A pointer is not required to be valid (that is, contain the address of an object during that object's lifetime) when it's first created.
A reference is another name for an object or function, not just that object's or function's address (this is why you don't use the * operator when working with references). You can't do pointer arithmetic on references, you can't assign arbitrary values to a reference, etc. When instantiated, a reference must refer to a valid object or function. How exactly references are represented internally isn't specified.
This is the C terminology - the C++ terminology is a little different.
In case it isn't clear by now I consider the T* p; idiom to be poor practice and responsible for no small amount of confusion about pointer declaration syntax; however, since that's how the C++ community has decided to do things, that's how I write my C++ code. I don't like it and it makes me itch, but it's not worth the heartburn to argue over it or to have inconsistently formatted code.
Simple answer:
Reference variables are an alias to the data passed to them, another label.
int var = 0;
int& refVar = var;
In practical terms, var and refVar are the same object.
Its worth noting that references to heap pointer data cannot deallocate (delete) the data, as its an alias of the data;
int* var = new int{0};
int& refVar = *var;
delete refVar // error
and references to the pointer itself can deallocate (delete) the data, as its an alias of the pointer.
int* var = new int{0};
int*& refVar = var;
delete refVar // good
I'm trying to understand how "pointer to member" works but not everything is clear for me.
Here is an example class:
class T
{
public:
int a;
int b[10];
void fun(){}
};
The following code ilustrate the problem and contains questions:
void fun(){};
void main()
{
T obj;
int local;
int arr[10];
int arrArr[10][10];
int *p = &local; // "standard" pointer
int T::*p = &T::a; // "pointer to member" + "T::" , that is clear
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
int *pA = arr; // ok
int T::*pA = T::b; // error
int (T::*pA)[10] = T::b; // error
int (T::*pA)[10] = &T::b; //works;
//1. Why "&" is needed for "T::b" ? For "standard" pointer an array name is the representation of the
// address of the first element of the array.
//2. Why "&" is not needed for the pointer to member function ? For "standard" pointer a function name
// is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
// That's rule works there.
//3. Why the above pointer declaration looks like the following pointer declaration ?:
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
system("pause");
}
Why "&" is needed for "T::b" ?
Because the standard requires it. This is to distinguish it from accessing a static class member.
From a standard draft n3337, paragraph 5.3.1/4, emphasis mine:
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed
in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because
there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to
member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. — end note]
For "standard" pointer an array name is the representation of the address of the first element of the array.
Not really. An array automatically converts to a pointer to first element, where required. The name of an array is an array, period.
Why "&" is not needed for the pointer to member function ?
It is needed. If your compiler allows it, it's got a bug. See the standardese above.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
The same thing aplies here as for arrays. There's an automatic conversion but otherwise a function has got a function type.
Consider:
#include <iostream>
template<typename T, size_t N>
void foo(T (&)[N]) { std::cout << "array\n"; }
template<typename T>
void foo(T*) { std::cout << "pointer\n"; }
int main()
{
int a[5];
foo(a);
}
Output is array.
Likewise for functions pointers:
#include <iostream>
template<typename T>
struct X;
template<typename T, typename U>
struct X<T(U)> {
void foo() { std::cout << "function\n"; }
};
template<typename T, typename U>
struct X<T(*)(U)> {
void foo() { std::cout << "function pointer\n"; }
};
void bar(int) {}
int main()
{
X<decltype(bar)> x;
x.foo();
}
Output is function.
And a clarification about this, because I'm not sure what exactly your comment is meant to say:
int arrArr[10][10];
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
Again, array-to-pointer conversion. Note that the elements of arrArr are int[10]s. pAA points to the first element of arrArr which is an array of 10 ints located at &arrArr[0]. If you increment pAA it'll be equal to &arrArr[1] (so naming it pA would be more appropriate).
If you wanted a pointer to arrArr as a whole, you need to say:
int (*pAA)[10][10] = &arrArr;
Incrementing pAA will now take you just past the end of arrArr, that's 100 ints away.
I think the simplest thing is to forget about the class members for a moment, and recap pointers and decay.
int local;
int array[10];
int *p = &local; // "standard" pointer to int
There is a tendency for people to say that a "decayed pointer" is the same as a pointer to the array. But there is an important difference between arr and &arr. The former does not decay into the latter
int (*p_array_standard)[10] = &arr;
If you do &arr, you get a pointer to an array-of-10-ints. This is different from a pointer to an array-of-9-ints. And it's different from a pointer-to-int. sizeof(*p_array_standard) == 10 * sizeof(int).
If you want a pointer to the first element, i.e. a pointer to an int, with sizeof(*p) == sizeof(int)), then you can do:
int *p_standard = &(arr[0);
Everything so far is based on standard/explicit pointers.
There is a special rule in C which allows you to replace &(arr[0]) with arr. You can initialize an int* with &(arr[0]) or with arr. But if you actually want a pointer-to-array, you must do int (*p_array_standard)[10] = &arr;
I think the decaying could almost be dismissed as a piece of syntactic sugar. The decaying doesn't change the meaning of any existing code. It simply allows code that would otherwise be illegal to become legal.
int *p = arr; // assigning a pointer with an array. Why should that work?
// It works, but only because of a special dispensation.
When an array decays, it decays to a pointer to a single element int [10] -> int*. It does not decay to a pointer to the array, that would be int (*p)[10].
Now, we can look at this line from your question:
int (T::*pA3)[10] = T::b; // error
Again, the class member is not relevant to understanding why this failed. The type on the left is a pointer-to-array-of-ints, not a pointer-to-int. Therefore, as we said earlier, decaying is not relevant and you need & to get the pointer-to-array-of-ints type.
A better question would be to ask why this doesn't work (Update: I see now that you did have this in your question.)
int T::*pA3 = T::b;
The right hand side looks like an array, and the left hand side is a pointer to a single element int *, and therefore you could reasonably ask: Why doesn't decay work here?
To understand why decay is difficult here, let's "undo" the syntactic sugar, and replace T::b with &(T::b[0]).
int T::*pA3 = &(T::b[0]);
I think this is the question that you're interested in. We've removed the decaying in order to focus on the real issue. This line works with non-member objects, why doesn't it work with member objects?
The simple answer is that the standard doesn't require it. Pointer-decay is a piece of syntactic sugar, and they simply didn't specify that it must work in cases like this.
Pointers-to-members are basically a little fussier than other pointers. They must point directly at the 'raw' entity as it appears in the object.
(Sorry, I mean it should refer (indirectly) by encoding the offset between the start of the class and the location of this member. But I'm not very good at explaining this.)
They can't point to sub-objects, such as the first element of the array, or indeed the second element of the array.
Q: Now I have a question of my own. Could pointer decay be extended to work on member arrays like this? I think it makes some sense. I'm not the only one to think of this! See this discussion for more. It's possible, and I guess there's nothing stopping a compiler from implementing it as an extension. Subobjects, including array members, are at a fixed offset from the start of the class, so this is pretty logical.
The first thing to note is that arrays decay into pointers to the first element.
int T::*pA = T::b;
There are two issues here, or maybe one, or more than two... The first is the subexpression T::b. The b member variable is not static, and cannot be accessed with that syntax. For pointer to members you need to always use the address-of operator:
int T::*pa = &T::b; // still wrong
Now the problem is that the right hand side has type int (T::*)[10] that does not match the left hand side, and that will fail to compile. If you fix the type on the left you get:
int (T::*pa)[10] = &T::b;
Which is correct. The confusion might have risen by the fact that arrays tend to decay to the first element, so maybe the issue was with the previous expression: int *p = a; which is transformed by the compiler into the more explicit int *p = &a[0];. Arrays and functions have a tendency to decay, but no other element in the language does. And T::b is not an array.
Edit: I skipped the part about functions...
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
It might not be as clear as it seems. The statement void (T::*pf)() = T::fun; is illegal in C++, the compiler you use is accepting it for no good reason. The correct code is the last one: void (T::*pf)() = &T::fun;.
int (T::*pA)[10] = &T::b; //works;
3.Why the above pointer declaration looks like the following pointer declaration ?
int (*pAA)[10] = arrArr;
To understand this, we needn't confuse ourselves with member arrays, simple arrays are good enough. Say've we two
int a[5];
int a_of_a[10][5];
The first (left-most) dimension of the array decays and we get a pointer to the first element of the array, when we use just the array's name. E.g.
int *pa = a; // first element is an int for "a"
int (*pa_of_a)[5] = a_of_a; // first element is an array of 5 ints for "a_of_a"
So without using & operator on the array, when we assign its name to pointers, or pass it to function as arguments, it decays as explained and gives a pointer to its first element. However, when we use the & operator, the decay doesn't happen since we're asking for the address of the array and not using the array name as-is. Thus the pointer we get would be to the actual type of the array without any decay. E.g.
int (*paa) [5] = &a; // note the '&'
int (*paa_of_a) [10][5] = &a_of_a;
Now in your question the upper declaration is a pointer to an array's address without the decay (one dimension stays one dimension), while the lower declaration is a pointer to an array name with decay (two dimensions become one dimension). Thus both the pointers are to an array of same single dimension and look the same. In our example
int (*pa_of_a)[5]
int (*paa) [5]
notice that the types of these pointers are the same int (*) [5] although the value they point to are of different array's.
Why "&" is needed for "T::b" ?
Because that's how the language is specified. It was decided not to complicate the language with a member-to-pointer conversion just for the sake of saving a single character even though, for historical reasons, we have similar conversions for arrays and functions.
For "standard" pointer an array name is the representation of the address of the first element of the array.
No it isn't; it's convertible to a pointer to its first element due to an arcane conversion rule inherited from C. Unfortunately, that's given rise to a widespread (and wrong) belief that an array is a pointer. This kind of confusion is probably part of the reason for not introducing similar bizarre conversions for member pointers.
Why "&" is not needed for the pointer to member function ?
It is. However, your compiler accepts the incorrect void main(), so it may accept other broken code.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
Again, the function name isn't a pointer; it's just convertible to one.
Why the above pointer declaration looks like the following pointer declaration ?
One is a pointer to an array, the other is a pointer to a member array. They are quite similar, and so look quite similar, apart from the difference which indicates that one's a member pointer and the other's a normal pointer.
Because T on it's own already has a well defined meaning: the type Class T. So things like T::b are logically used to mean members of Class T. To get the address of these members we need more syntax, namely &T::b. These factors don't come into play with free functions and arrays.
A pointer to a class or struct type points to an object in memory.
A pointer to a member of a class type actually points to an offset from the start of the object.
You can think of these kind of pointers as pointers to blocks of memory. These need an actual address and offset, hence the &.
A pointer to function points to the access point of the function in the assembly code. A member method in general is the same as a function that passes a this pointer as the first argument.
That's in crude nut shell the logic behind needing a & to get the address for members and object address in general.
void (*pF)() = fun; //here also everything is clear
It doesn't work because function fun is undefined
int T::*pA = T::b; // error
What is T::b? T::b is not static member. So you need specific object. Instead write
int *pA = &obj.b[0];
Similarly,
int (T::*pA)[10] = &T::b; //works;
It can be compiled. But it will not work as you expected. Make b static or call obj.b to get access to defined member of defined object. We can easily check this. Create conctructor for your class T
class T
{
public:
T() {
a = 444;
}
int a;
int b[10];
void fun(){}
};
On what value points pA ?
int T::*pA = &T::a;
*pA doesn't not point on variable with value 444, because no object has been created, no constructor has been called.
I'm trying to understand how "pointer to member" works but not everything is clear for me.
Here is an example class:
class T
{
public:
int a;
int b[10];
void fun(){}
};
The following code ilustrate the problem and contains questions:
void fun(){};
void main()
{
T obj;
int local;
int arr[10];
int arrArr[10][10];
int *p = &local; // "standard" pointer
int T::*p = &T::a; // "pointer to member" + "T::" , that is clear
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
int *pA = arr; // ok
int T::*pA = T::b; // error
int (T::*pA)[10] = T::b; // error
int (T::*pA)[10] = &T::b; //works;
//1. Why "&" is needed for "T::b" ? For "standard" pointer an array name is the representation of the
// address of the first element of the array.
//2. Why "&" is not needed for the pointer to member function ? For "standard" pointer a function name
// is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
// That's rule works there.
//3. Why the above pointer declaration looks like the following pointer declaration ?:
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
system("pause");
}
Why "&" is needed for "T::b" ?
Because the standard requires it. This is to distinguish it from accessing a static class member.
From a standard draft n3337, paragraph 5.3.1/4, emphasis mine:
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed
in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because
there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to
member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. — end note]
For "standard" pointer an array name is the representation of the address of the first element of the array.
Not really. An array automatically converts to a pointer to first element, where required. The name of an array is an array, period.
Why "&" is not needed for the pointer to member function ?
It is needed. If your compiler allows it, it's got a bug. See the standardese above.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
The same thing aplies here as for arrays. There's an automatic conversion but otherwise a function has got a function type.
Consider:
#include <iostream>
template<typename T, size_t N>
void foo(T (&)[N]) { std::cout << "array\n"; }
template<typename T>
void foo(T*) { std::cout << "pointer\n"; }
int main()
{
int a[5];
foo(a);
}
Output is array.
Likewise for functions pointers:
#include <iostream>
template<typename T>
struct X;
template<typename T, typename U>
struct X<T(U)> {
void foo() { std::cout << "function\n"; }
};
template<typename T, typename U>
struct X<T(*)(U)> {
void foo() { std::cout << "function pointer\n"; }
};
void bar(int) {}
int main()
{
X<decltype(bar)> x;
x.foo();
}
Output is function.
And a clarification about this, because I'm not sure what exactly your comment is meant to say:
int arrArr[10][10];
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
Again, array-to-pointer conversion. Note that the elements of arrArr are int[10]s. pAA points to the first element of arrArr which is an array of 10 ints located at &arrArr[0]. If you increment pAA it'll be equal to &arrArr[1] (so naming it pA would be more appropriate).
If you wanted a pointer to arrArr as a whole, you need to say:
int (*pAA)[10][10] = &arrArr;
Incrementing pAA will now take you just past the end of arrArr, that's 100 ints away.
I think the simplest thing is to forget about the class members for a moment, and recap pointers and decay.
int local;
int array[10];
int *p = &local; // "standard" pointer to int
There is a tendency for people to say that a "decayed pointer" is the same as a pointer to the array. But there is an important difference between arr and &arr. The former does not decay into the latter
int (*p_array_standard)[10] = &arr;
If you do &arr, you get a pointer to an array-of-10-ints. This is different from a pointer to an array-of-9-ints. And it's different from a pointer-to-int. sizeof(*p_array_standard) == 10 * sizeof(int).
If you want a pointer to the first element, i.e. a pointer to an int, with sizeof(*p) == sizeof(int)), then you can do:
int *p_standard = &(arr[0);
Everything so far is based on standard/explicit pointers.
There is a special rule in C which allows you to replace &(arr[0]) with arr. You can initialize an int* with &(arr[0]) or with arr. But if you actually want a pointer-to-array, you must do int (*p_array_standard)[10] = &arr;
I think the decaying could almost be dismissed as a piece of syntactic sugar. The decaying doesn't change the meaning of any existing code. It simply allows code that would otherwise be illegal to become legal.
int *p = arr; // assigning a pointer with an array. Why should that work?
// It works, but only because of a special dispensation.
When an array decays, it decays to a pointer to a single element int [10] -> int*. It does not decay to a pointer to the array, that would be int (*p)[10].
Now, we can look at this line from your question:
int (T::*pA3)[10] = T::b; // error
Again, the class member is not relevant to understanding why this failed. The type on the left is a pointer-to-array-of-ints, not a pointer-to-int. Therefore, as we said earlier, decaying is not relevant and you need & to get the pointer-to-array-of-ints type.
A better question would be to ask why this doesn't work (Update: I see now that you did have this in your question.)
int T::*pA3 = T::b;
The right hand side looks like an array, and the left hand side is a pointer to a single element int *, and therefore you could reasonably ask: Why doesn't decay work here?
To understand why decay is difficult here, let's "undo" the syntactic sugar, and replace T::b with &(T::b[0]).
int T::*pA3 = &(T::b[0]);
I think this is the question that you're interested in. We've removed the decaying in order to focus on the real issue. This line works with non-member objects, why doesn't it work with member objects?
The simple answer is that the standard doesn't require it. Pointer-decay is a piece of syntactic sugar, and they simply didn't specify that it must work in cases like this.
Pointers-to-members are basically a little fussier than other pointers. They must point directly at the 'raw' entity as it appears in the object.
(Sorry, I mean it should refer (indirectly) by encoding the offset between the start of the class and the location of this member. But I'm not very good at explaining this.)
They can't point to sub-objects, such as the first element of the array, or indeed the second element of the array.
Q: Now I have a question of my own. Could pointer decay be extended to work on member arrays like this? I think it makes some sense. I'm not the only one to think of this! See this discussion for more. It's possible, and I guess there's nothing stopping a compiler from implementing it as an extension. Subobjects, including array members, are at a fixed offset from the start of the class, so this is pretty logical.
The first thing to note is that arrays decay into pointers to the first element.
int T::*pA = T::b;
There are two issues here, or maybe one, or more than two... The first is the subexpression T::b. The b member variable is not static, and cannot be accessed with that syntax. For pointer to members you need to always use the address-of operator:
int T::*pa = &T::b; // still wrong
Now the problem is that the right hand side has type int (T::*)[10] that does not match the left hand side, and that will fail to compile. If you fix the type on the left you get:
int (T::*pa)[10] = &T::b;
Which is correct. The confusion might have risen by the fact that arrays tend to decay to the first element, so maybe the issue was with the previous expression: int *p = a; which is transformed by the compiler into the more explicit int *p = &a[0];. Arrays and functions have a tendency to decay, but no other element in the language does. And T::b is not an array.
Edit: I skipped the part about functions...
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
It might not be as clear as it seems. The statement void (T::*pf)() = T::fun; is illegal in C++, the compiler you use is accepting it for no good reason. The correct code is the last one: void (T::*pf)() = &T::fun;.
int (T::*pA)[10] = &T::b; //works;
3.Why the above pointer declaration looks like the following pointer declaration ?
int (*pAA)[10] = arrArr;
To understand this, we needn't confuse ourselves with member arrays, simple arrays are good enough. Say've we two
int a[5];
int a_of_a[10][5];
The first (left-most) dimension of the array decays and we get a pointer to the first element of the array, when we use just the array's name. E.g.
int *pa = a; // first element is an int for "a"
int (*pa_of_a)[5] = a_of_a; // first element is an array of 5 ints for "a_of_a"
So without using & operator on the array, when we assign its name to pointers, or pass it to function as arguments, it decays as explained and gives a pointer to its first element. However, when we use the & operator, the decay doesn't happen since we're asking for the address of the array and not using the array name as-is. Thus the pointer we get would be to the actual type of the array without any decay. E.g.
int (*paa) [5] = &a; // note the '&'
int (*paa_of_a) [10][5] = &a_of_a;
Now in your question the upper declaration is a pointer to an array's address without the decay (one dimension stays one dimension), while the lower declaration is a pointer to an array name with decay (two dimensions become one dimension). Thus both the pointers are to an array of same single dimension and look the same. In our example
int (*pa_of_a)[5]
int (*paa) [5]
notice that the types of these pointers are the same int (*) [5] although the value they point to are of different array's.
Why "&" is needed for "T::b" ?
Because that's how the language is specified. It was decided not to complicate the language with a member-to-pointer conversion just for the sake of saving a single character even though, for historical reasons, we have similar conversions for arrays and functions.
For "standard" pointer an array name is the representation of the address of the first element of the array.
No it isn't; it's convertible to a pointer to its first element due to an arcane conversion rule inherited from C. Unfortunately, that's given rise to a widespread (and wrong) belief that an array is a pointer. This kind of confusion is probably part of the reason for not introducing similar bizarre conversions for member pointers.
Why "&" is not needed for the pointer to member function ?
It is. However, your compiler accepts the incorrect void main(), so it may accept other broken code.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
Again, the function name isn't a pointer; it's just convertible to one.
Why the above pointer declaration looks like the following pointer declaration ?
One is a pointer to an array, the other is a pointer to a member array. They are quite similar, and so look quite similar, apart from the difference which indicates that one's a member pointer and the other's a normal pointer.
Because T on it's own already has a well defined meaning: the type Class T. So things like T::b are logically used to mean members of Class T. To get the address of these members we need more syntax, namely &T::b. These factors don't come into play with free functions and arrays.
A pointer to a class or struct type points to an object in memory.
A pointer to a member of a class type actually points to an offset from the start of the object.
You can think of these kind of pointers as pointers to blocks of memory. These need an actual address and offset, hence the &.
A pointer to function points to the access point of the function in the assembly code. A member method in general is the same as a function that passes a this pointer as the first argument.
That's in crude nut shell the logic behind needing a & to get the address for members and object address in general.
void (*pF)() = fun; //here also everything is clear
It doesn't work because function fun is undefined
int T::*pA = T::b; // error
What is T::b? T::b is not static member. So you need specific object. Instead write
int *pA = &obj.b[0];
Similarly,
int (T::*pA)[10] = &T::b; //works;
It can be compiled. But it will not work as you expected. Make b static or call obj.b to get access to defined member of defined object. We can easily check this. Create conctructor for your class T
class T
{
public:
T() {
a = 444;
}
int a;
int b[10];
void fun(){}
};
On what value points pA ?
int T::*pA = &T::a;
*pA doesn't not point on variable with value 444, because no object has been created, no constructor has been called.
In C++, is this form int *p semantically different than this one int* p? Or is this clearly a matter of style?
Now this question may be dumb, but I remember that I had seen somewhere both styles being used at the same time, something that led to me to believe that there may be different semantics between those forms.
They're the same.
That's tricky sometimes, since
int* a, b;
defines one pointer and one int. This style makes it more clear:
int *a, b;
It has the same semantic meaning.
If you are using const keyword be aware of the caveats:
int * conts p; - const pointer to int versus
int const * p; - non const pointer to const int.
As others have said, they're the same.
The fact that int* a, b; declares one pointer and one integer is one aspect of a wart that manifests in other ways too. E.g.:
int* a, f(double), c[42];
declares a pointer to int called a, a function that takes a double and returns an int called f, and an array of 42 ints called c. That's because all of these "decorations" (*, (), []) form part of the C++ grammar called the declarator, which is associated with an individual name, rather than with the statement as a whole (which is called a declaration in the grammar).
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
c++ * vs & in function declaration
I know that this probably seems like an incredibly elementary question to many of you, but I have genuinely had an impossible time finding a good, thorough explanation, despite all my best Googling. I'm certain that the answer is out there, and so my search terms must be terrible.
In C++, a variety of symbols and combinations thereof are used to mark parameters (as well as arguments to those parameters). What, exactly, are their meanings?
Ex: What is the difference between void func(int *var) and void func(int **var)? What about int &var?
The same question stands for return types, as well as arguments. What does int& func(int var) mean, as compared to int* func(int var)? And in arguments, how does y = func(*x) differ from y = func(&x)?
I am more than happy to read enormous volumes on the subject if only you could point me in the right direction. Also, I'm extremely familiar with general programming concepts: OO, generics/templates, etc., just not the notation used in C/C++.
EDIT: It seems I may have given the impression that I do not know what pointers are. I wonder how that could be :)
So for clarification: I understand perfectly how pointers work. What I am not grasping, and am weirdly unable to find answers to, is the meaning of, for example 'void func(int &var)'. In the case of an assignment statement, the '&' operator would be on the right hand side, as in 'int* x = &y;', but in the above, the '&' operator is effectively on the left hand side. In other words, it is operating on the l-value, rather than the r-value. This clearly cannot have the same meaning.
I hope that I'm making more sense now?
To understand this you'll first need to understand pointers and references. I'll simply explain the type declaration syntax you're asking about assuming you already know what pointers and references are.
In C, it is said that 'declaration follows use.' That means the syntax for declaring a variable mimics using the variable: generally in a declaration you'll have a base type like int or float followed something that looks like an expression. For example in int *y the base type is int and the expression look-alike is *y. Thereafter that expression evaluates to a value with the given base type.
So int *y means that later an expression *y is an int. That implies that y must be a pointer to an int. The same holds true for function parameters, and in fact for whole function declarations:
int *foo(int **bar);
In the above int **bar says **bar is an int, implying *bar is a pointer to an int, and bar is a pointer to a pointer to an int. It also declares that *foo(arg) will be an int (given arg of the appropriate type), implying that foo(arg) results in a pointer to an int.¹ So the whole function declaration reads "foo is a function taking a pointer to a pointer to an int, and returning a pointer to an int."
C++ adds the concept of references, and messes C style declarations up a little bit in the process. Because taking the address of a variable using the address-of operator & must result in a pointer, C doesn't have any use for & in declarations; int &x would mean &x is an int, implying that x is some type where taking the address of that type results in an int.² So because this syntax is unused, C++ appropriates it for a completely different purpose.
In C++ int &x means that x is a reference to an int. Using the variable does not involve any operator to 'dereference' the reference, so it doesn't matter that the reference declarator symbol clashes with the address-of operator. The same symbol means completely different things in the two contexts, and there is never a need to use one meaning in the context where the other is allowed.
So char &foo(int &a) declares a function taking a reference to an int and returning a reference to a char. func(&x) is an expression taking the address of x and passing it to func.
1. In fact in the original C syntax for declaring functions 'declarations follow use' was even more strictly followed. For example you'd declare a function as int foo(a,b) and the types of parameters were declared elsewhere, so that the declaration would look exactly like a use, without the extra typenames.
2. Of course int *&x; could make sense in that *&x could be an int, but C doesn't actually do that.
What you're asking about are called pointers (*), and reference to (&), which I think is best explained here.
The symbols & and * are used to denote a reference and pointer type, respectively.
int means simply the type 'int',
int* means 'pointer to int',
int& means 'reference to int',
A pointer is a variable which is used to store the address of a variable.
A reference has the syntax of its base type, but the semantics of a pointer to that type. This means you don't need to dereference it in order to change the value.
To take an example, the following code blocks two are semantically equivalent:
int* a = &value;
*a = 0;
And:
int& a = value;
a = 0;
The main reasons to use pointers or references as an argument type is to avoid copying of objects and to be able to change the value of a passed argument. Both of these work because, when you pass by reference, only the address is copied, giving you access to the same memory location as was "passed" to the function.
In contrast, if a reference or pointer type is not used, a full copy of the argument will be made, and it is this copy which is available inside the function.
The symbols * and & have three meanings each in C++:
When applied to an expression, they mean "dereference" and "address-of" respectively, as you know.
When part of a type, they mean "pointer" and "reference", respectively.
Since C++ doesn't care about arbitrary spacing, the declaration int *ptr is exactly the same as the declaration int* ptr, in which you can now more clearly see that this is an object called ptr of type int*.1
When used between two expressions, they mean "multiply" and "bitwise AND", respectively.
1 - though, frustratingly, this isn't actually how the internal grammar reads it, thanks to the nasty legacy of C's type system. So avoid single-line multi-declarations involving pointers unless you want a surprise.
Ex: What is the difference between 'void func(int *var)' and 'void
func(int **var)'? What about 'int &var'?
The same question stands for return types, as well as arguments. What
does 'int& func(int var)' mean, as compared to 'int* func(int var)'?
And in arguments, how does 'y = func(*x)' differ from 'y = func(&x)'?
(1)
<return type> <function name> <parameters>
void func (int *var)
<parameter> here int *var is a pointer to integer, ie it can point to
an array or any buffer that should be handled with integer pointer
arithmetic. In simple terms , var holds the address of the respective
**actual parameter.**
eg: int arr[10];
func(arr);
int a = 33;
func(&a);
Here, &a means we are explicitly passing address of the the variable 'a'.
(2)
int m = 0;
int &var = m;
Here var means reference, ie it another alias name for variable 'm' ,
so any change 'var' makes will change the contents of variable 'm'.
var = 2; /* will change the actual contents of 'm' */
This simple example will not make sense , unless you understand the context.
Reference are usually use to pass parameter to function, so that changes made by
the function to the passed variable is visible at the caller.
int swap(int &m, int &n) {
tmp = m;
m = n;
n = tmp;
}
void main( void ) {
int x = 1, y = 2;
swap(x, y);
/* x = 2, y =1 */
}
(3)
'int& func(int var)' mean, as compared to 'int* func(int var)'?
int& func(int var) means the function returns a reference;
int* func(int var) means the function returns a pointer / address;
Both of the them has its context;
int& setNext() {
return next;
}
setNext() = previous;
where as
int* setNext() {
return &next;
}
int *inptr;
inptr = setNext();
*inptr = previous;
In the previous two lines,
int *inptr <- integer pointer declaration;
*inptr <- means we are accessing contents of the address pointed by inptr;
ie we are actually referring to 'next' variable.
The actual use is context specific. It can't be generalized.
(4)
how does 'y = func(*x)' differ from 'y = func(&x)'?
y = func(&x) is already explained.
y = func(*x) , well i'm not sure if you actually meant *x.
int swap(int *m, int *n) {
tmp = *m;
*m = *n;
*n = tmp;
}