- C编程教程
- C语言 - 首页
- C语言基础
- C语言 - 概述
- C语言 - 特性
- C语言 - 历史
- C语言 - 环境搭建
- C语言 - 程序结构
- C语言 - Hello World
- C语言 - 编译过程
- C语言 - 注释
- C语言 - 词法单元
- C语言 - 关键字
- C语言 - 标识符
- C语言 - 用户输入
- C语言 - 基本语法
- C语言 - 数据类型
- C语言 - 变量
- C语言 - 整数提升
- C语言 - 类型转换
- C语言 - 类型强制转换
- C语言 - 布尔值
- C语言中的常量和字面量
- C语言 - 常量
- C语言 - 字面量
- C语言 - 转义序列
- C语言 - 格式说明符
- C语言中的运算符
- C语言 - 运算符
- C语言 - 算术运算符
- C语言 - 关系运算符
- C语言 - 逻辑运算符
- C语言 - 位运算符
- C语言 - 赋值运算符
- C语言 - 一元运算符
- C语言 - 自增和自减运算符
- C语言 - 三元运算符
- C语言 - sizeof 运算符
- C语言 - 运算符优先级
- C语言 - 其他运算符
- C语言中的决策机制
- C语言 - 决策机制
- C语言 - if 语句
- C语言 - if...else 语句
- C语言 - 嵌套 if 语句
- C语言 - switch 语句
- C语言 - 嵌套 switch 语句
- C语言中的循环
- C语言 - 循环
- C语言 - while 循环
- C语言 - for 循环
- C语言 - do...while 循环
- C语言 - 嵌套循环
- C语言 - 无限循环
- C语言 - break 语句
- C语言 - continue 语句
- C语言 - goto 语句
- C语言中的函数
- C语言 - 函数
- C语言 - 主函数
- C语言 - 按值调用函数
- C语言 - 按引用调用函数
- C语言 - 嵌套函数
- C语言 - 可变参数函数
- C语言 - 用户自定义函数
- C语言 - 回调函数
- C语言 - 返回语句
- C语言 - 递归
- C语言中的作用域规则
- C语言 - 作用域规则
- C语言 - 静态变量
- C语言 - 全局变量
- C语言中的数组
- C语言 - 数组
- C语言 - 数组的特性
- C语言 - 多维数组
- C语言 - 将数组传递给函数
- C语言 - 从函数返回数组
- C语言 - 变长数组
- C语言中的指针
- C语言 - 指针
- C语言 - 指针和数组
- C语言 - 指针的应用
- C语言 - 指针算术
- C语言 - 指针数组
- C语言 - 指针指针
- C语言 - 将指针传递给函数
- C语言 - 从函数返回指针
- C语言 - 函数指针
- C语言 - 指向数组的指针
- C语言 - 指向结构体的指针
- C语言 - 指针链
- C语言 - 指针与数组的区别
- C语言 - 字符指针和函数
- C语言 - 空指针
- C语言 - void 指针
- C语言 - 悬空指针
- C语言 - 解引用指针
- C语言 - 近指针、远指针和巨指针
- C语言 - 指针数组的初始化
- C语言 - 指针与多维数组的区别
- C语言中的字符串
- C语言 - 字符串
- C语言 - 字符串数组
- C语言 - 特殊字符
- C语言中的结构体和联合体
- C语言 - 结构体
- C语言 - 结构体和函数
- C语言 - 结构体数组
- C语言 - 自引用结构体
- C语言 - 查找表
- C语言 - 点号 (.) 运算符
- C语言 - 枚举 (enum)
- C语言 - 结构体填充和打包
- C语言 - 嵌套结构体
- C语言 - 匿名结构体和联合体
- C语言 - 联合体
- C语言 - 位域
- C语言 - typedef
- C语言中的文件处理
- C语言 - 输入输出
- C语言 - 文件 I/O(文件处理)
- C语言预处理器
- C语言 - 预处理器
- C语言 - 编译指示
- C语言 - 预处理器运算符
- C语言 - 宏
- C语言 - 头文件
- C语言中的内存管理
- C语言 - 内存管理
- C语言 - 内存地址
- C语言 - 存储类
- 其他主题
- C语言 - 错误处理
- C语言 - 可变参数
- C语言 - 命令执行
- C语言 - 数学函数
- C语言 - static 关键字
- C语言 - 随机数生成
- C语言 - 命令行参数
- C语言编程资源
- C语言 - 问答
- C语言 - 快速指南
- C语言 - 速查表
- C语言 - 有用资源
- C语言 - 讨论
C语言中的指针指针(双指针)
什么是C语言中的双指针?
C语言中的**指针指针**,也称为**双指针**,用于存储另一个指针的地址。
C语言中存储另一个变量地址的变量称为**指针**。指针变量可以存储任何类型的地址,包括基本数据类型、数组、结构体类型等。同样,指针也可以存储另一个指针的地址,在这种情况下,它被称为**“指针指针”**(也称为**“双指针”**)。
“指向指针的指针”是一种**多级间接寻址**或**指针链**的形式。通常,指针包含变量的地址。当我们定义“指向指针的指针”时,第一个指针包含第二个指针的地址,第二个指针指向包含实际值的位置,如下所示:
指针指针的声明
**指针指针**(**双指针**)的声明类似于指针的声明,唯一的区别是需要在指针变量名前使用一个额外的星号(**\***)。
示例
例如,以下声明声明了一个int类型的**指针指针**:
int **var;
当目标值由“指向指针的指针”间接指向时,访问该值需要应用两次星号运算符。
指针指针(双指针)示例
以下示例演示了在C语言中声明、初始化和使用指针指针(双指针)。
#include <stdio.h>
int main() {
// An integer variable
int a = 100;
// Pointer to integer
int *ptr = &a;
// Pointer to pointer (double pointer)
int **dptr = &ptr;
printf("Value of 'a' is : %d\n", a);
printf("Value of 'a' using pointer (ptr) is : %d\n", *ptr);
printf("Value of 'a' using double pointer (dptr) is : %d\n", **dptr);
return 0;
}
输出
Value of 'a' is : 100 Value of 'a' using pointer (ptr) is : 100 Value of 'a' using double pointer (dptr) is : 100
普通指针在C语言中是如何工作的?
假设一个整数变量**“a”**位于任意地址1000。它的指针变量是**“b”**,编译器为它分配地址2000。下图显示了可视化描述:
让我们声明一个指向int类型的指针,并将int变量的地址存储在其中。
int a = 10; int *b = &a;
**解引用运算符**通过指针获取值。
printf("a: %d \nPointer to 'a' is 'b': %d \nValue at 'b': %d", a, b, *b);
示例
这是一个完整的程序,显示了普通指针是如何工作的:
#include <stdio.h>
int main(){
int a = 10;
int *b = &a;
printf("a: %d \nPointer to 'a' is 'b': %d \nValue at 'b': %d", a, b, *b);
return 0;
}
输出
它将打印int变量的值、它的地址以及通过解引用指针获得的值:
a: 10 Pointer to 'a' is 'b': 6422036 Value at 'b': 10
双指针是如何工作的?
现在让我们声明一个可以存储“b”地址的指针,“b”本身是指向int类型的指针,写成**“int \*”**。
让我们假设编译器也为它分配地址3000。
因此,**“c”**是指向int类型的指针的指针,应该声明为**“int \*\*”**。
int **c = &b;
printf("b: %d \nPointer to 'b' is 'c': %d \nValue at b: %d\n", b, c, *c);
您可以获得“b”(它是“a”的地址)的值、“c”(它是“b”的地址)的值以及从“c”解引用的值(它是“a”的地址):
b: 6422036 Pointer to b is c: 6422024 Value at b: 6422036
这里,“c”是双指针。其声明中的第一个星号指向“b”,第二个星号依次指向“a”。因此,我们可以使用双重解引用指针从“c”获取“a”的值。
printf("Value of 'a' from 'c': %d", **c);
这应该显示'a'的值为10。
示例
这是一个完整的程序,显示了双指针是如何工作的:
#include <stdio.h>
int main(){
int a = 10;
int *b = &a;
printf("a: %d \nAddress of 'a': %d \nValue at a: %d\n\n", a, b, *b);
int **c = &b;
printf("b: %d \nPointer to 'b' is c: %d \nValue at b: %d\n", b, c, *c);
printf("Value of 'a' from 'c': %d", **c);
return 0;
}
输出
运行代码并检查其输出:
a: 10 Address of 'a': 1603495332 Value at a: 10 b: 1603495332 Pointer to 'b' is c: 1603495336 Value at b: 1603495332 Value of 'a' from 'c': 10
双指针的行为就像普通指针一样
C语言中的“指针指针”或“双指针”的行为就像普通指针一样。因此,双指针变量的大小始终等于普通指针。
我们可以通过对上述程序中的指针“b”和“c”应用**sizeof运算符**来检查它:
printf("Size of b - a normal pointer: %d\n", sizeof(b));
printf("Size of c - a double pointer: %d\n", sizeof(c));
这显示了两个指针的大小相等:
Size of b - a normal pointer: 8 Size of c - a double pointer: 8
**注意:**上述示例中显示的不同指针变量的大小和地址可能会有所不同,因为它取决于诸如CPU架构和操作系统之类的因素。但是,它们将显示一致的结果。
C语言中的多级指针(三级指针可能吗?)
理论上,指针声明中出现的星号数量没有限制。
如果您确实需要指向**“c”**(在上例中),它将是“指向指向指针的指针”,可以声明为:
int ***d = &c;
通常,双指针用于引用二维数组或字符串数组。