ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
> 成员指针请移步 *面向对象编程.类和对象.成员.成员指针* ## 一.指针 + 计算机存储器按照地址访问。 + 指针变量的值是一个地址。根据这个地址,可以访问存储器相应位置的数据。 ```[flow] addr=>operation: 地址 data=>operation: 数据 addr->data ``` + `NULL` 的值为0,表示空地址 + [11+] 可以用 `nullptr` 代表空指针 #### 1.指针的定义和初始化 **基本格式** ```c 类型 *标识符 = 初始地址; ``` 其中,指针指向的类型称为 **基类型**。 指针只能指向同一基类型的变量。唯一的例外是基类型为 `void` 的指针可以指向任意类型的数据。 > 定义语句中 `*` 只是一个修饰符,并不是类型的一部分。 ```c int *pi,i;//pi是指向整型数据的指针,i是整型变量 ``` > 为了避免一些奇葩的问题,建议指针一定义就赋初值。 #### 2.指针的解引用:通过指针变量的值去访问内存中相应位置的数据。 ``` int i = 1; int *pi = &i; *pi = 3; ``` #### 3.指针作函数参数 指针本身作为一个变量,仍然是 **按值传递** 。但是它传递的是其他变量的地址,因此在函数内可以通过传入的地址去修改变量的值。 ```c void swap(int *a,int *b) { int temp; temp = *a; *a = *b; *b = temp; } ``` #### 4.指针的计算 **偏移量** 就是基类型的大小, `sizeof(基类型)` > 基类型为 `void` 类型的指针不能参与运算,因为它的偏移量是不确定的。 **指针与整数的运算** 1. 指针与整数加减 结果为指针,其值为 `原来的值 ± 整数 * 偏移量` 2. 递增递减 指针自身的值变为 `原来的值 ± 偏移量` 3. 下标访问 结果为计算后指针的解引用,计算后指针的值与上面相同。 `a[b]` 等价于 `*(a+b)` **指针与指针的运算** 1. 指针与指针作减法 返回整数,其值为 `指针值的差 ÷ 偏移量` 。 2. 不存在指针与指针的加法。想想这操作有多可怕? ## 二.理解复杂的含指针表达式 #### 1.含 `const` 修饰符的指针变量的定义 指向常量的指针变量、指向变量的指针常量、指向常量的指针常量。 **例1** ```c const int *pci; ``` 这是一个 **指向常量的指针变量** 。 `pci` 先与 `*` 结合,表示这是一个指针; 再与 `const int`结合, 表示它指向一个整型常量。 需要注意的是,这里的 `const` 只影响 **通过指针访问数据** 这种方式: ```c int i = 600; const int *p = &i; i = 300;//对,原来的变量依然可修改。 *p = 150;//错,不能通过指针来修改原变量。 ``` **例2** ```c int * const cpi; ``` 这是一个 **指向变量的指针常量** 。 `cpi` 先与 `const` 结合,表示 `cpi` 是一个常量; 再与 `*`结合, 表示 `cpi` 是一个指针; 最后与 `int` 结合,表示它指向一个整型变量。 **例3** ```c const int * const cpci; ``` 这是一个 **指向常量的指针常量** 。 `cpci` 先与 `const` 结合,表示 `cpci` 是一个常量; 再与 `*`结合, 表示 `cpci` 是一个指针; 最后与 `const int` 结合,表示它指向一个整型常量。 **例4** ```c++ //将int*简化为PointerToInt typedef int* PointerToInt; //定义指针 const PointerToInt cpi; ``` 这是一个 **指向变量的指针常量** 。 首先需要注意的是 `typedef` 声明的别名并不是简单粗暴的替换。在 `typedef` 中,`*` 不是一个修饰符,而是类型的一部分。这意味着 `PointerToInt` 就是一个指针类型。需要注意的是,`*` 等符号的优先级没有改变。 所以 `cpi` 先与 `PointerToInt` 结合,表示 `cpi` 是一个指向整型变量的指针; 再与 `const` 结合,表示 `cpi` 是一个常量。 **例5 constexpr指针** \[11+\][$] 与 `const` 不同的是, `constexpr` 只对指针本身有效,对指向的值无效。 `constexpr` 指针可以指向一个常量,也可以指向一个非常量,但只能指向一个静态存储区的量,如全局变量。 ```c++ const int size = 50; constexpr int *ps = &size; ``` #### 2.指针数组与指向数组的指针 **例6** ```c++ int *arrpi[5]; ``` 这是一个 **指向整型变量的指针的数组** 。 因为 `[]` 的优先级比 `*` 高,所以 `arrpi` 先与 `[5]` 结合,表示 `arrpi` 是一个有5个元素的数组; 再与 `*` 结合,表示每个元素是指针类型; 最后与 `int` 结合,表示每个元素是整型变量。 **例7** ``` int (*parri)[5]; ``` 这是一个 **指向整型数组的指针** 。 `parri` 先与 `*` 结合,说明 `parri` 是一个指针; 再与 `[5]` 结合,说明 `parri` 指向一个数组; 最后与 `int` 结合,说明 `parri` 指向一个整型的数组。 #### 3.指向函数的指针和返回指针的函数声明 **例8** ``` int (*pf)(int,int); ``` 这是一个 **指向函数的指针** 。 `pf` 先与 `*` 结合,说明 `pf` 是一个指针; 再与 `(int,int)` 结合,说明 `pf` 指向参数为 `int` 和 `int` 的函数; 再与 `int` 结合,说明 `pf` 指向返回值为 `int` 的函数。 **例9** ```c int* f(int,int); ``` 这是一个 **返回指针的函数声明** 。 `f` 先与 `(int,int)` 结合,说明它是一个参数为 `int` 和 `int` 的函数; 再与 `*`结合,说明它返回一个指针。 最后与 `int` 结合,说明返回的指针指向 `int` 。 #### 4.指向指针的指针 **例10** ```c int **p; ``` 这是一个 **指向指针的指针** 。 `p` 先与 `*` 结合,说明 `p` 是一个指针。 再与 `*` 结合,说明 `p` 指向一个指针。 再与 `int` 结合,说明 `p` 指向一个整型指针。 **从上面的例子可以看出,任何复杂含指针表达式的分析,都是从标识符开始,从右往左分析,并注意符号优先级。** 下面给出常用定义或声明表达式的优先级(由高到低): | 符号|含义| | ----|----| | []|数组下标| | ()|括号/函数参数表| | \*|指针声明| | & |引用声明|