- int *p[2]
- int (*p)[2]
- int (*p)()
Example 1
int *p[2];This is actually an array of two int pointers. We can also think of this as a pointer to two consecutive int pointers.
int *p[2]; int *a = new int; *a = 21; int *b = new int; *b = 22; p[0] = a; p[1] = b; std::cout << *p[0] << std::endl; // 21 std::cout << *p[1] << std::endl; // 22 int **q = p; std::cout << **q << std::endl; std::cout << **(q + 1) << std::endl; delete a; delete b;http://codepad.org/6c07RgKf
Example 2
int (*p)[2];This is a pointer to an array of two ints. Just as in the first example, we can think of this a pointer to a pointer, since an array is basically a const pointer.
int n[2]; n[0] = 4; n[1] = 7; int (*p)[2] = &n; std::cout << (*p)[0] << std::endl; // 4 std::cout << (*p)[1] << std::endl; // 7 // or ... std::cout << **p << std::endl; // 4 std::cout << *(*p + 1) << std::endl; // 7http://codepad.org/UDcH5cIQ
Example 3
int (*p)();This is a pointer to a function returning an int.
int takeThisInt()
{
return 123;
}
// ...
int (*p)() = &takeThisInt;
int x = p(); // note the parentheses
std::cout << x << std::endl; // 123http://codepad.org/iL701mg5Pointer-to-member-function syntax
This pointer-to-member-function syntax in C++ is not exactly making things more intuitive. Here is an example:void (SomeClass::*x)(int) const = &SomeClass::func2;Hmm… Let's take a look at the context in which this statement appears.
class SomeClass
{
public:
void func1(int x) const { std::cout << "func 1: " << x; }
void func2(int x) const { std::cout << "func 2: " << x; }
void func3(int x) const { std::cout << "func 3: " << x; }
};
void callSomeFunction(void (SomeClass::*m)(int) const)
{
SomeClass obj;
(obj.*m)(1);
}
int main()
{
void (SomeClass::*x)(int) const;
x = &SomeClass::func2;
callSomeFunction(x); // func 2: 1
return 0;
}http://codepad.org/eUtSGfbVIn main(), void (SomeClass::*x)(int) const introduces a pointer (named x) to a const member function of SomeClass that returns void and takes an int as parameter. Then, &SomeClass::func2 takes the address of func2, which happens to fit this description. Finally, in callSomeFunction(), the supplied function pointee is called with the argument 1 on the stack allocated object.
A typedef can help to make this a bit more readable:
typedef void (SomeClass::*SomeClassMember)(int) const;The program now reads:
class SomeClass
{
public:
void func1(int x) const { std::cout << "func 1: " << x; }
void func2(int x) const { std::cout << "func 2: " << x; }
void func3(int x) const { std::cout << "func 3: " << x; }
};
typedef void (SomeClass::*SomeClassMember)(int) const;
void callSomeFunction(SomeClassMember m)
{
SomeClass obj;
(obj.*m)(1);
}
int main()
{
SomeClassMember x = &SomeClass::func2;
callSomeFunction(x);
return 0;
}Ok, this post was supposed to be about the reference-to-pointer syntax.Reference vs. Pointer
Pointers are memory addresses with type information. The type specifies the kind of data stored in the pointed-to address. References are typically implemented as pointers by the compiler, but on the syntactic level there are several differences:- A reference can't, once created, be changed to reference another object.
int n = 1; int *p = &n; // p points to n int k = 2; p = &k; // p now points to k instead int &r = n; // r will always reference n
- References cannot be null.
int *p = new int;
*p = 123;
int &x = *p; // x is now a local reference to p
x = 5;
std::cout << *p << std::endl; // 5
delete p;
p = 0; // pointer is now NULL
if (p) { // we can't do this with a reference
*p = 1;
}
x = 3; // undefined behavior- References must be initialized when created, and cannot be uninitialized.
int &ref; // error: ‘ref’ declared as reference but not initialized
Why reference-to-pointer?
Let's look at some different function declarations to see how the reference-to-pointer syntax can be useful.- void takeInt(int x);
- void takeIntRef(int &r);
- void takePtr(int *p);
- void takePtrToPtr(int **p);
- void takeRefToPtr(int *&rp);
void takeInt(int x); void takeIntRef(int &r); void takePtr(int *p);The first three cases are straighforward:
- The int is passed by value, which means that a local copy is made.
- The int is passed by reference, the local name
acts as an alias for the original variable. - A pointer is passed, similar to passing a reference but less safe.
Note that a pointer is actually passed by value, i.e., only a copy of the pointer is passed to the function. The address of the int's memory location is copied to the local pointer p.
void takePtrToPtr(int **p);This is a bit more interesting. A pointer to a pointer is passed. Suppose that a points to b, and b points to an int.
a → b → int
Passing (a) to the function, we can now change not only the original int pointee, but also the pointer (b) itself. Here is an example:
void takePtrToPtr(int **p)
{
int *x = new int;
*x = 123;
*p = x;
}
int main()
{
int n = 1;
int *p = &n;
assert(p == &n);
takePtrToPtrcout << *p; // 123
delete p; // no leaks ^_^
return 0;
}Finally,void takeRefToPtr(int *&rp);is similar to the pointer-to-pointer approach, but with a slightly more friendly syntax. We are now passing a reference to the pointer to takeRefToPtr().
void takeRefToPtr(int *&rp)
{
int *x = new int;
*x = 123;
rp = x;
}
int main()
{
int n = 55;
int *p = &n;
takeRefToPtr(p);
assert(p != &n);
std::cout << *p << std::endl; // 123;
delete p;
return 0;
}Note how the function changes the the original pointer p.We could think of the relationship
- int *x ↔ int *&x
as similar to that between
- int x ↔ int &x.
Finally, here is a program that demonstrates the use of the reference-to-pointer syntax:
#include <iostream>
#include <assert.h>
static int five = 5;
static int nine = 9;
void takeInt(int x)
{
x = 0;
}
void takeIntRef(int &r)
{
r = 0;
}
void takePtr(int *p)
{
*p = 1;
p = &five;
}
void takePtrToPtr(int **p)
{
**p = 789;
*p = &five;
}
void takeRefToPtr(int *&rp)
{
*rp = 1;
rp = &nine;
}
int main()
{
int n = 123;
takeInt(n);
// local copy is modified
std::cout << n << std::endl;
// 123 (value unchanged)
takeIntRef(n);
// value passed by reference, original is modified
std::cout << n << std::endl;
// 0 (assigned in function)
int *pt = &n;
// pt points to n
takePtr(pt);
// pointer is passed by value
assert(pt == &n);
// pointer has not changed (p still points to n) ...
std::cout << n << std::endl;
// 1 ... but pointee has
takePtrToPtr(&pt);
// pass a pointer to pt (= pointer to a pointer to n)
assert(pt != &n);
// this time the pointer has changed,
// pt now no longer points to n
std::cout << *pt << std::endl;
// 5
assert(pt == &five);
// indeed, pt points to the static "five"
std::cout << n << std::endl;
// 789 (changed in first line of takePtrToPtr)
takeRefToPtr(pt);
// pass a pointer by reference
std::cout << *pt << std::endl;
// 9 (pt is now modified in function)
return 0;
}http://codepad.org/3OD0sVvw




1 comments:
Great Explain!
Post a Comment