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.
Consider the code:
void foo(char a[]){
a++; // works fine, gets compiled
//...
}
Now, consider this:
void foo(){
char a[50];
a++; // Compiler error
//...
}
I heard an array is equivalent to a constant pointer and can't be incremented as it is not a lvalue...
Then why does first code gets compiled, is it so because array arguments to functions are passed as a pointer, i.e. T[] is converted to T* for passing..
So, foo(a) passes a as a pointer.
But is it not back converted to T[] again because is declared as:
void foo(char a[]);
When you pass an array as an argument to a function, it decays to a pointer.
So the thing you increment inside the function body is a pointer, not an array.
This is a rather unfortunate feature inherited from the C language, with the rather yucky name of "decay." Since C once did not allow passing compound types by value, they decided to allow programmers to specify arrays as function parameter types, but only cosmetically. The array type decays to a pointer type, implementing a sort of pass-by-reference semantic different from the rest of the language. Ugly.
To recap (and others have already said this), the signature
void foo(char a[]); // asking for trouble
is unceremoniously mangled into
void foo(char *a);
… all for the sake of compatibility with ancient C code. Since you aren't writing ancient C code, you should not make use of this "feature."
However, you can cleanly pass a reference to an array. C++ requires that the size of the array be known:
void foo( char (&a)[ 50 ] );
Now a cannot be modified within the function (edit: its contents can, of course — you know what I mean), and only arrays of the right size may be passed. For everything else, pass a pointer or a higher-level type.
I heard an array is equivalent to a constant pointer
You can think of it that way, but they're not equivalent.
An array decays to a pointer when passed to a function, that's why inside the function it's valid.
Just because the signature is void foo(char a[]) doesn't make a an array.
Outside the function, it's just an array, and you can't do pointer arithmetics on it.
In C++, any function parameter of type "array of T" is adjusted to be "pointer to T". Try this code:
void foo(char a[]) {}
void foo(char* a) {} //error: redefinition
They are indeed the same function.
So, why can we pass an array argument to a function as a pointer parameter? Not because an array is equivalent to a constant pointer, but because an array type can be implicitly converted to an rvalue of pointer type. Also note the result of the conversion is an rvalue, that's why you can't apply the operator ++ to an array, you can only apply this operator to an lvalue.
I heard an array is equivalent to a constant pointer and can't be incremented as it is not a lvalue...
Almost.
An array expression is a non-modifiable lvalue; it may not be an operand to operators such as ++ or --, and it may not be the target of an assignment expression. This is not the same thing as a constant pointer (that is, a pointer declared as T * const).
An array expression will be replaced with a pointer expression whose value is the address of the first element of the array except when the array expression is an operand of the sizeof or unary & operators, or when the array expression is a string literal being used to initialize another array in a declaration.
When you call a function with an array argument, such as
int a[N];
...
foo(a);
the expression a is converted from type "N-element array of int" to "pointer to int" and this pointer value is what gets passed to foo; thus, the corresponding function prototype should be
void foo (int *arr) {...}
Note that in the context of a function parameter declaration, T a[] and T a[N] are identical to T *a; in all three cases, a is declared as a pointer to T. Within the function foo, the parameter arr is a pointer expression, which is a modifiable lvalue, and as such it may be assigned to and may be the operand of the ++ and -- operators.
Remember that all these conversions are on the array expression; that is, the array identifier or other expression that refers to the array object in memory. The array object (the chunk of memory holding the array values) is not converted.
When you pass an array a[] to a function, it passes the value of 'a', an address, into the function. so you can use it as a pointer in the function. If you declare an array in the function, 'a' is constant because you can't change its address in memory.
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;
}