C语言中的指针的指针(双重指针)

你好,有抱负的程序员们!今天,我们将踏上一段激动人心的旅程,深入探讨指针的世界——特别是指针的指针。我知道你可能会想:“指针?双重指针?这听起来像是个噩梦!”但别担心,我承诺会尽可能让这个过程既有趣又易于理解。所以,拿起你最喜欢的饮料,放松一下,让我们开始吧!

C - Pointer to Pointer

C语言中的双重指针是什么?

想象你正在参加寻宝活动。你有一张地图(我们称之为指针),它指引你找到一个宝箱。但惊喜的是!在宝箱里,还有另一张地图(另一个指针),它指引你找到真正的宝藏。本质上,双重指针就是这样——一个指向另一个指针的指针。

在C语言编程中,双重指针正如其名——一个指向指针的指针。它是一个存储另一个指针地址的变量。这听起来一开始可能有点令人困惑,但别担心,我们会一步一步地分解。

指针的指针声明

让我们从如何声明双重指针开始。语法非常简单:

int **ptr;

在这里,ptr 是一个指向指针的指针,它指向一个整数。第一个星号 * 使它成为一个指针,第二个 * 使它成为一个指向指针的指针。

指针的指针(双重指针)示例

让我们看一个简单的例子来更好地理解这一点:

#include <stdio.h>

int main() {
int x = 5;
int *p = &x;
int **pp = &p;

printf("x的值: %d\n", x);
printf("使用p的x的值: %d\n", *p);
printf("使用pp的x的值: %d\n", **pp);

return 0;
}

输出:

x的值: 5
使用p的x的值: 5
使用pp的x的值: 5

让我们分解一下:

  1. 我们声明一个整数 x 并初始化为5。
  2. 我们创建一个指针 p,它指向 x
  3. 我们创建一个双重指针 pp,它指向 p
  4. 然后我们用三种不同的方式打印 x 的值:
  • 直接使用 x
  • 使用单指针 p(我们用 *p 解引用一次)
  • 使用双重指针 pp(我们用 **pp 解引用两次)

所有三种方法都给我们相同的值:5。就像使用不同的地图找到宝藏一样!

C语言中的普通指针如何工作?

在我们深入探讨双重指针之前,让我们快速回顾一下普通指针是如何工作的:

int y = 10;
int *q = &y;

printf("y的值: %d\n", y);
printf("y的地址: %p\n", (void*)&y);
printf("q的值: %p\n", (void*)q);
printf("q指向的值: %d\n", *q);

输出:

y的值: 10
y的地址: 0x7ffd5e8e9f44
q的值: 0x7ffd5e8e9f44
q指向的值: 10

在这里,q 是一个存储 y 地址的指针。当我们使用 *q 时,我们正在访问存储在该地址的值。

双重指针如何工作?

现在,让我们扩展到双重指针:

int z = 15;
int *r = &z;
int **rr = &r;

printf("z的值: %d\n", z);
printf("z的地址: %p\n", (void*)&z);
printf("r的值: %p\n", (void*)r);
printf("r的地址: %p\n", (void*)&r);
printf("rr的值: %p\n", (void*)rr);
printf("r指向的值: %d\n", *r);
printf("rr指向的值: %p\n", (void*)*rr);
printf("rr指向的指向的值: %d\n", **rr);

输出:

z的值: 15
z的地址: 0x7ffd5e8e9f48
r的值: 0x7ffd5e8e9f48
r的地址: 0x7ffd5e8e9f50
rr的值: 0x7ffd5e8e9f50
r指向的值: 15
rr指向的值: 0x7ffd5e8e9f48
rr指向的指向的值: 15

这看起来可能有点令人不知所措,但让我们分解一下:

  1. z 是一个值为15的整数。
  2. r 是一个存储 z 地址的指针。
  3. rr 是一个存储 r 地址的双重指针。
  4. *r 给我们 z 的值(15)。
  5. *rr 给我们 r 的值(即 z 的地址)。
  6. **rr 给我们 z 的值(15)。

可以这样想:rr 指向 rr 指向 z。所以 **rr 就像是在说“跟随第一个指针,然后跟随第二个指针,给我那里的值”。

双重指针表现得就像普通指针一样

这里有个小秘密:双重指针只是一个指针,但它指向的不是整数或浮点数,而是另一个指针。这意味着我们可以对双重指针做所有我们可以对普通指针做的事情。

例如,我们可以将双重指针与数组一起使用:

int main() {
char *fruits[] = {"苹果", "香蕉", "樱桃"};
char **ptr = fruits;

for(int i = 0; i < 3; i++) {
printf("%s\n", *ptr);
ptr++;
}

return 0;
}

输出:

苹果
香蕉
樱桃

在这个例子中,fruits 是一个指针数组(每个指针指向一个字符串),而 ptr 是一个指向字符指针的指针(可以指向 fruits 的元素)。

C语言中的多级指针(三级指针可能吗?)

是的,你可以有三级指针、四级指针等等!理论上,你可以有无限级别的间接引用。然而,在实践中,看到超过双重指针的情况很少。

这里有一个三级指针的例子:

int x = 5;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;

printf("x的值: %d\n", ***ppp);

输出:

x的值: 5

但请记住,仅仅因为你可以,并不意味着你应该。多级间接引用可能会使代码更难阅读和维护。正如古老的编程格言所说,“计算机科学中的所有问题都可以通过增加一个间接引用级别来解决……除了太多的间接引用级别问题!”

结论

恭喜你!你刚刚穿越了C语言中双重指针的复杂水域。记住,就像编程中的许多概念一样,指针的指针一开始可能看起来令人困惑,但通过练习,它们会变得 second nature。

以下是我们所涵盖的关键点的总结表格:

概念 语法 描述
普通指针 int *p; 指向一个整数
双重指针 int **pp; 指向一个指向整数的指针
解引用 *p 访问 p 指向的值
双重解引用 **pp 访问 pp 指向的指针所指向的值
地址运算符 &x 获取 x 的地址

继续练习,保持好奇心,记住——每个专家都曾是初学者。祝你编程愉快!

Credits: Image by storyset