We already discussed some of these topics, but pointers are very important, so we want to make sure everyone is comfortable with them.
We have stressed so far that every expression has a type and a value.
We know that the value of &n is the address of variable
n. However, we haven't discussed that type of &n
until now. The type of &n is int*. Following the same idea,
we can consider the following types as well:
|
|
In general:
int* is a type, we can declare a variable of this type as
follows:
int* p;
p is a memory address.
int n = 1;
int* p;
p = &n; // This assignment makes sense: typeof(p) = int* = typeof(&n)
Indeed, if you have an address, you can access an object at that address in
memory. We call this operation is "dereference". The deference operator is
*.
In a sense, we have two operators having the opposite direction from each other. In particular:
Consider the following code snippet:
|
|
|
What will be the output of code on the right?
Answer: 10 5 |
p points to b (i.e. holds the address of
b). Therefore, *p is really b, which
means that *p = 5 will change the value of b to 5.
|
The picture shows that there are two ways to access an object:
Follow the arrow!
|
|
p[i] is equivalent to *(p+i)
|
// mem.cpp
1 #include <iostream>
2 #include <string>
3 using namespace std;
4
5 int main()
6 {
7 int a = 10, b = 7;
8 int* p;
9
10 cout << "&a=" << &a << ", &b=" << &b << ", &p=" << &p << endl;
11 cout << "a=" << a << ", b=" << b << endl;
12
13 uint64_t addr; // uint64_t: 64-bit unsigned integer
14 cin >> hex >> addr; // hex: read in the hexadecimal format
15 p = (int*) addr; // now p contains the address from the terminal
16
17 cout << "*p=" << *p << endl;
18 return 0;
19 }
A sample run up to line 13 is given below:
&a=0x7ffff83497e0, &b=0x7ffff83497e4, &p=0x7ffff83497e8 a=10, b=7
0x7ffff83497e0.
Answer: (Make sure you can draw the following diagram by youself).
address value (variables) ... 0x7ffff83497e0 10 a 0x7ffff83497e4 7 b 0x7ffff83497e8 0x7ffff83497e0 p ...
10
*p corresponds to an int
object at address 0x7ffff83497e0. Well, the int object at address
0x7ffff83497e0 is actually the variable a.
|
|
| operator | in a variable declaration | in an expression |
| * | declaring a pointer type
int* p;
| dereference (*p) = 3;
|
| & | address-of
int* p;
|
int* p; // this is a declaration
// * means pointer declaration
*p = 7; // *p is an expression; the* is used as a unary rather than binary operator
// * means dereference
cout << 3*7; // 3*7 is an expression, and the* is used as a binary operator
// * means multiplication
For example, if x is of type int, then &x is of type int*;
if p is of type int*, then &p is of type int**.
For example, if p is of type int*, then *p is of type int;
if pp is of type int**, then *pp is of type int*;
|
|