正如我们所知,指针用于在C语言中存储变量的地址。指针可以减少访问变量的时间。然而,在C语言中,我们也可以定义一个指针来存储另一个指针的地址。这样的指针被称为双指针(指向指针)。第一个指针用于存储变量的地址,而第二个指针用于存储第一个指针的地址。让我们通过下面的图示来理解。

声明双指针的语法如下:

int **p; // 指向整数的指针的指针

考虑以下示例:

cCopy code
#include <stdio.h>

void main()
{
    int a = 10;
    int *p;
    int **pp;
    p = &a;      // 指针p指向变量a的地址
    pp = &p;     // 双指针pp指向指针p的地址
    printf("a的地址:%x\n", &a);     // 输出a的地址
    printf("p的地址:%x\n", p);      // 输出p的地址
    printf("p指针存储的值:%d\n", *p);   // 输出p指针存储的值,即a的值
    printf("pp的地址:%x\n", pp);    // 输出pp的地址
    printf("pp指针存储的值:%d\n", **pp);  // 输出pp指针存储的值,即a的值
}

输出结果

cssCopy code
a的地址:d26a8734
p的地址:d26a8738
p指针存储的值:10
pp的地址:d26a8738
pp指针存储的值:10

C双指针示例

让我们看一个示例,其中一个指针指向另一个指针的地址。

p2包含p的地址(fff2),p包含number变量的地址(fff4)。

#include<stdio.h>

int main() {
    int number = 50;
    int *p; // 指向整型的指针
    int **p2; // 指向指针的指针

    p = &number; // 存储number变量的地址
    p2 = &p;

    printf("number变量的地址为 %x \n", &number);
    printf("p变量的地址为 %x \n", p);
    printf("p变量的值为 %d \n", *p);
    printf("p2变量的地址为 %x \n", p2);
    printf("p2指针所指向的值为 %d \n", **p2);

    return 0;
}

以下是给您重新翻译后的C语言教程,代码已经使用代码块展示:

cCopy code
#include<stdio.h>

int main() {
    int number = 50;
    int *p; // 指向整型的指针
    int **p2; // 指向指针的指针

    p = &number; // 存储number变量的地址
    p2 = &p;

    printf("number变量的地址为 %x \n", &number);
    printf("p变量的地址为 %x \n", p);
    printf("p变量的值为 %d \n", *p);
    printf("p2变量的地址为 %x \n", p2);
    printf("p2指针所指向的值为 %d \n", **p2);

    return 0;
}

输出结果

cssCopy code
number变量的地址为 fff4
p变量的地址为 fff4
p变量的值为 50
p2变量的地址为 fff2
p2指针所指向的值为 50

问:下面这个程序的输出是什么?

#include <stdio.h>

int main()
{
   int a[10] = {100, 206, 300, 409, 509, 601}; // 第1行
   int *p[] = {a, a+1, a+2, a+3, a+4, a+5};    // 第2行
   int **pp = p;                              // 第3行

   pp++;                                       // 第4行
   printf("%d %d %d\n", pp - p, *pp - a, **pp); // 第5行

   *pp++;                                     // 第6行
   printf("%d %d %d\n", pp - p, *pp - a, **pp); // 第7行

   ++*pp;                                     // 第8行
   printf("%d %d %d\n", pp - p, *pp - a, **pp); // 第9行

   ++**pp;                                    // 第10行
   printf("%d %d %d\n", pp - p, *pp - a, **pp); // 第11行

   return 0;
}

解释

在上述问题中,使用了双指针进行指针运算。定义了一个包含6个元素的数组a,由指针数组p指向。指针数组p由双指针pp指向。然而,上面的图片给出了关于如何分配内存给数组a和指针数组p的简要概念。p的元素是指向数组a的每个元素的指针。由于我们知道数组名包含数组的基地址,因此可以通过使用(a)、(a+1)等方式来遍历数组的值。如图所示,a[0]可以通过以下方式访问:

  • a[0]:这是访问数组第一个元素的最简单方式。
  • *(a):由于a存储了数组的第一个元素的地址,可以通过对其进行间接指针访问来获取其值。
  • p[0]:如果要通过指针p来访问a[0],可以在指针数组p的第一个元素上使用间接操作符(),即*p[0]。
  • (pp):由于pp存储了指针数组的基地址,*pp将给出指针数组的第一个元素的值,即整数数组的第一个元素的地址。pp将给出整数数组的第一个元素的实际值。

接下来讨论程序,第1行和第2行分别声明了整数数组和指针数组。第3行将双指针初始化为指针数组p。如图所示,如果数组的地址从200开始,整数的大小为2,则指针数组的值将为200、202、204、206、208、210。假设指针数组的基地址为300,双指针pp包含指针数组的地址,即300。第4行将pp的值增加1,即pp现在指向地址302。

第5行包含一个表达式,打印了三个值,即pp - p、pp - a、*pp。让我们计算每个值。

  • pp = 302,p = 300 => pp - p = (302-300)/2 => pp - p = 1,即打印1。
  • pp = 302,pp = 202,a = 200 => pp - a = 202 - 200 = 2/2 = 1,即打印1。
  • pp = 302,pp = 202,(*pp) = 206,即打印206。

因此,作为第5行的结果,将在控制台上打印输出1、1、206。第6行写入pp++。在这里,我们必须注意,两个一元运算符和++具有相同的优先级。因此,按照结合律规则,它将从右到左进行评估。因此,表达式pp++可以重写为((pp++))。由于pp = 302,现在它变成了304。*pp将给出204。

第7行再次写入表达式,打印了三个值,即pp - p、pp - a、pp。让我们计算每个值。

  • pp = 304,p = 300 => pp - p = (304 - 300)/2 => pp - p = 2,即打印2。
  • pp = 304,pp = 204,a = 200 => pp - a = (204 - 200)/2 = 2,即打印2。
  • pp = 304,pp = 204,(*pp) = 300,即打印300。

因此,作为第7行的结果,将在控制台上打印输出2、2、300。第8行写入++pp。根据结合律规则,这可以重写为(++((pp)))。由于pp = 304,pp = 204,pp = *(p[2]) = 206,现在它将指向a[3]。

第9行再次写入表达式,打印了三个值,即pp - p、pp - a、pp。让我们计算每个值。

  • pp = 304,p = 300 => pp - p = (304 - 300)/2 => pp - p = 2,即打印2。
  • pp = 304,pp = 206,a = 200 => pp - a = (206 - 200)/2 = 3,即打印3。
  • pp = 304,pp = 206,(*pp) = 409,即打印409。

因此,作为第9行的结果,将在控制台上打印输出2、3、409。第10行写入++pp。根据结合律规则,这可以重写为(++(((pp))))。pp = 304,pp = 206,pp = 409,++pp => pp = *pp + 1 = 410。换句话说,a[3] = 410。

第11行再次写入表达式,打印了三个值,即pp - p、pp - a、pp。让我们计算每个值。

  • pp = 304,p = 300 => pp - p = (304 - 300)/2 => pp - p = 2,即打印2。
  • pp = 304,pp = 206,a = 200 => pp - a = (206 - 200)/2 = 3,即打印3。
  • 在第8行中,**pp = 410。

因此,作为第11行的结果,将在控制台上打印输出2、3、410。

  • 输出
1 1 206
2 2 300
2 3 409
2 3 410 

标签: c语言, c语言教程, c语言技术, c语言学习, c语言学习教程, c语言下载, c语言开发, c语言入门教程, c语言进阶教程, c语言高级教程, c语言面试题, c语言笔试题, c语言编程思想