指针与引用
指针与引用
关于指针的两大运算符:
*:称为间接访问或是解除引用运算符。将其运用于指针,可以得到该指针对应的地址处存储的值。
&:称为地址运算符,对一个变量应用地址运算符,就可以获取它的地址。
实际上,由于指针也是一个变量,因此一个指针也可以再取地址,这个地址需存入一个二维指针,不过高维的情形非常复杂,不用担心在考试中遇到。
指针的定义声明
声明一个指针,可以任意指定类型,甚至 * 两边的空格也是任选的,但对每个指针变量名,都需要使用一个*。
int *a;
char* b;
double*c;
第一句声明表明: \(*a\) 的类型为 int,由于 * 运算符被用于指针,因此变量 \(a\) 本身必须为指针.
在口头和书面语表述上,我们说 a 指向 int 类型。
指针定义声明实例
在下面的例子中,假设内存地址从 \(100\) 开始(方便起见,其为十进制数,实际上你在 C++ 程序直接 cout一个地址值,是十六进制的)。
// 内存地址 : |a 100|b 104|c 108|d 112|
int a = 123;
double b = 3.14;
int *c = &a;
double* d = &b;
cout << a << " " << b << " " << c << " " << d << endl;
则最后会输出:
123 3.14 100 104
数组与指针的关系
int a[10];
在上面的声明中,显然 \(a[4]\) 是整型(\(int\))但 \(a\) 的类型是什么? 它表示的又是什么?
在几乎所有使用数组名的表达式中, 数组名(上面的a)的值是一个指针常量,也就是数组第 1 个元素的地址。
在上面的例子中, a 的类型是“指向 int 的常量指针”;如果它是其他类型,那么数组名的类型就是“指向其他类型的常量指针”。
注意这个值是指针常量,而不是指针变量。显然表示完整一段元素的数组的起始位置的指针,是不能轻易改变的——你不能很轻松地移动整个数组。
数组的下标引用表达式
∗(a + i) = a[i]
这两个间接访问与下标引用的表达式是等价的。实际上,写在程序语句中,会有运算优先级上的轻微差异。
int array[10];
int *ap = array + 2;
尝试在以下涉及 ap 的表达式中,写出使用 array的对等表达式:
-
ap:显然,
array+2与array[2]符合要求。 -
*ap:间接访问跟随指针访问它所指向的位置,因此答案为 array[2],
*(array+2)也可以。 -
ap[0]:如果你觉得 ap 不是一个数组从而不能这样做,你就陷入了其他编程语言的思维惯性中了。 C++的下标引用和间接访问表达式一样,在这种情况下,对等的表达式是
*(ap+(0)), \(0\) 和括号可以除去,其结果与前一个表达式相同:array[2]。 -
ap+6:如果
ap指向array[2],这个加法运算产生的指针所指向的元素是array[2]向后移动 \(6\) 个整数位置的元素。对等表达式为array + 8、array[8]。 -
*ap+6:小心!这里的两个操作符中,是间接访问先执行!间接访问的结果再与 \(6\) 相加,所以这个表达式相当于表达式
array[2]+6。 -
*(ap+6):有了上面的例子,不难想到,这一表达式的值为
array[8]。 -
ap:注意,这一表达式是合法、能通过编译的,但其结果与 array 无关。你无法预测编译器会把
ap放在相对于array的什么内存位置。 -
ap[-1]:我们常说的“负数下标会报错”在这里不能直接适用,应该先转换为间接访问表达式:
*(array + 2 - 1),从而可知:答案为array[1]。 -
ap[9]:问题在于,原数组
array只有 \(10\) 个元素,所以会有溢出错误。 -
2[array]:你也许想不到,这个表达式是合法的,它的值就是 array[2]!因为这里的加法是满足交换律的, $$a+i = i+a$$。
指针的指针
int a = 12, *b = &a, **c = &b;
对上述代码, \(c\) 的类型显然是一个指针。
但 \(b\) 是一个“指向 int 的指针”,则 \(c\) 是一个指向“指向 int 的指针”的指针。
确切的说,这里的 \(c\) 是一个指针的指针,这样的定义是合法的,指针的指针同样可以进行间接访问 * 操作。
对于 ***c, * 操作符具有从右向左的结合性,因此这个表达式相当于 * (**c)。
以下每一行,列出了一个表达式和与之含义相同的表达式。
- \(a\):等价于 12。
- \(b\):等价于 &a。
- *\(b\):等价于 a, 12。
- \(c\):等价于 &b。
- ***\(c\):等价于 *b, a, 12。
注意到之前已经引入了形如 *(a + i) = a[i] 的写法,这里的 \(a\) 是指向数组第一个元素的指针,是 int*/int[] 类型,而 \(i\) 是一个位置下标,是 int 类型。
两者不仅可以做加法,还可以做减法,只是对于数组,要注意“加减法”所表示的数组下标移动不要越界。
注意:虽然 C++ 的基础类型在计算机中实际占据的位(bit)不同,但指针的“加减法”所表示的地址在内存中的移动,已经考虑到每次移动的位和指针指向数据类型的位一样了。
long long a[10], *b = a+1; // a[1]
char c[5], *d = c+2; // c[2]
完结撒花~~~

浙公网安备 33010602011771号