《指针的编程艺术(第二版)》一3.6 多重指针

简介:

本节书摘来自异步社区《指针的编程艺术(第二版)》一书中的第3章,第3.6节,作者 蔡明志,更多章节内容可以访问云栖社区“异步社区”公众号查看

3.6 多重指针

指针的编程艺术(第二版)
多重指针(multiple pointer){XE "多重指標(multiple pointer)"},指的是在一个语句中有2个或以上的*。我们以范例starstarPointer-3来说明。

范例starstarPointer-3

/* starstarPointer-3.c */
#include <stdio.h>
#include <conio.h>

int main()
{
  int i[5]={10, 20, 30, 40, 50};
  int *ptr[] = {i, i+1, i+2, i+3, i+4};
  int **p2 = ptr;
  int k;

  for(k=0; k<5; k++)
    printf("*ptr[%d]=%d\n", k, *ptr[k]);

  printf("\n");
  for(k=0; k<5; k++)
    printf("**(p2+%d) = %d\n", k, **(p2+k));
  getch();
  return 0;
}

输出结果


e5fc15dbd1cac3a2dddd1480c4059a17ae43014f

程序中

  int *ptr[] = {i, i+1, i+2, i+3, i+4};```
表示ptr是一个数组,这个数组有5个元素,每个元素都是指向int的指针,也可以说ptr与一个数组指针p2需经过两次的间接访问才能得到值,用图表示如下。

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/b9766579fc4db4f637cd296fb5fcc46bab42b8f0.png" >
</div>

从图中可以很容易地得到答案。

比较复杂的是当*和++或--混合使用时就必须非常小心,分析++或--是作用于地址还是值。请参阅范例starstarPointer-5.c。

范例starstarPointer-5.c

/ starstarPointer-5.c /

include

include

int main()
{
  int i[] = {10, 20, 30, 40, 50};
  int *pa[] = {i, i+2, i+1, i+4, i+3};
  int **p2 = pa;
  printf("Initial p2 = %dn", p2);
  p2++;
  printf("After p2++, the  p2 = %dn", p2);
  ++*p2;
  printf("After ++*p2, the p2 = %dn", p2);
  **p2++;
  printf("After p2++, the p2 = %dn", **p2);
  ++**p2;
  printf("After ++p2, the p2 = %dn", **p2);
  system("PAUSE");
  return 0;
}

输出结果

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/5b46091d54ba500a713e88dc5d5b06b3d958e92c.png" >
</div>

我们用图来辅助说明以上的变量定义。i数组定义如下

  int i[] = {10, 20, 30, 40, 50};`
表示i是5个元素的数组,其示意图如下所示。


3cc38e5c332a0288bd794707bfa3cb92813b813a

而 pa 数组定义如下

  int *pa[] = {i, i+2, i+1, i+4, i+3};```
表示pa是一个数组指针,其中pa[0]、pa[1]、…、pa[4],分别指向i数组的某一元素的地址,其示意图如下所示。

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/a4c9bf0f3c8dd090bb9c5f06bf9fa3e7f5c9fbc7.png" >
</div>
而p2变量定义如下。

    int **p2 = pa;`
表示p2为一个指向指针的指针,初始值为pa(pa[0]的地址),注意,p2是指针变量。整个程序的示意图如下所示。


752332d4f71d6645f562501e2aa6743709975b2e

我们来剖析程序中的问题。注意图形中的粗线条。

1. p2++;
由于p2++会更新p2的值,而其值原来是pa,无论是前置+还是后继+,p2都会往前一个元素,此时的p2是pa+1,所以 **p2 等于 30。


07597036b16de8da6d1a07d50602fdba7c869afe

2. ++*p2;
由于++和具有相同的运算优先级,而其结合性由右至左,因此,++就是针对p2所指向的地址加1。


d3c0ebcaea12fbe747b86a5a40d0488209df715c

  注意p2是pa[1],pa[1]的值原先是指向i+2,经过++p2之后,p2的地址将更新为i+3,所以*p2的值是40。

3. **p2++;
由于和++的运算优先级相同,但其结合性是由右至左,因此p2++实际上是(p2++);虽然p2++先做,不过此处的++是后置加,因此会先将它搁在一边,处理完*之后,再执行加1,所以就这条语句而言,只是对p2的地址指向下一个而已,示意图如下。


29a6bb94ad4375b1c036abd218f9b1079240ef80

原先p2指向pa+1,所以p2++则是指向pa+2,**p2也就等于20。

4. ++**p2;
这条语句的++是针对p2加1,p2的结果是一个值,获取后将它加1,便是最后的答案。


fb3d4a491be1c8e4cb6cfe6db5e9a04ea98a2cf2

原先的**p2是20,因此加1之后,成为21。

综上所述,读者应该可以了解*和++的使用,是对哪一个地址加1,或对哪一个数值加1,由于++的作用会将原先的地址或变量值加以更新,这里使用粗线条表示其路线。

最后,以3个 的指针作为结尾,请参阅范例starstarstarPointer-5。其余的4个、5个 的指针就留给读者自行研究了。

范例starstarstarPointer-5

/* starstarstarPointer-5.c */
#include <stdio.h>
#include <stdlib.h>

int main()
{
  char *s[] = {"Stanford", "University", "California", "America"};
  char **sa[] = {s, s+1, s+2, s+3};
  char ***p3 = sa;
  printf("**p3++ = %s\n", **p3++);
  printf("**++p3 = %s\n", **++p3);
  printf("**++*p3 = %c\n", **++*p3);
  printf("*(*--*++p3+3) = %c\n", *(*--*++p3+3));
  system("PAUSE");
  return 0;
}

输出结果


a4b0b4d6a33dfcf80ec02e219b9a0f51e1961bdc

程序中有一条语句如下
  char *s[] = {“Stanford”, “University”, “”, “”};```
得知s是一个数组指针,每一个元素都指向字符的指针,其示意图如下。

<div style="text-align: center">
 <img src="https://yqfile.alicdn.com/ab179014f98285584d3e680bba88bd6e04fb63e5.png" >
</div>

接下来的语句

  char **sa[] = {s, s+1, s+2, s+3};`
sa的每一个元素为指向指针的指针,其示意图如下。


ee505f9b4d4b8ffb3a25885aeed3ac139369e606

最后,p3为3个指针,其初始值为sa,注意p3为指针变量,其示意图如下。


d3110a249aee849089a5c19a106ba0372a5b88db

现在看看printf中的语句

**p3++;
由于此处++为后继加,当处理完整个语句后,才会对p3加1(也就是向前挪一个元素),因此,当它输出Stanford字符串后,p3移到sa+1的地方。如下图所示。


2ac7152f1414664f7dcb98079bc3e45cf5097732

接下来的**++p3与上一语句不同处在于,此处的++是前置加,因此先对p3向前一元素,再输出字符串,结果为California。如下图所示。


b6f9fca82ae9a29cfb98efddb429ed96f6e62188

++p3的++作用于p3,而p3为sa[2],其值指向s+2,因此sa[2]的值将更改为指向s+3,所以++p3以%c输出的结果为A字符。如下图所示。


d1b1cf7da9481dfcbb513e57058436e140517fb7

最后一个语句虽然很长,但并不难,让我们来剖析一下。


90a16f358c37c66dbb6aba8dafd31f32a6434544

因此,语句中的--是针对sa[3]的内容减1,


268a86bd50b197d48676e450dd2d473e69dc2fce

所以(--*++p3+3)的值为i。

当递增运算符(++)、递减运算符(--)与指针运算符()同时出现在一条语句时,必须要掌握++与--的作用点在哪里。由于这3个运算符的运算优先级是相同的,此时必须运用其结合性来由右至左执行。以--++ptr为例,由于结合性由右至左,所以先执行++ptr,再处理(++ptr),接着对++ptr执行--,到此为止,++和--都是针对地址在做运算,最后再执行(--++ptr),这才是值,因为有2个,这才符合访问值的条件。

相关文章
|
7月前
|
存储 Oracle Java
Java11--ZGC--权衡--ZGC--GC术语--着色指针--多重映射--读屏障标记--重定位
Java11--ZGC--权衡--ZGC--GC术语--着色指针--多重映射--读屏障标记--重定位
132 0
|
7月前
|
程序员 C++
多重指针
多重指针
60 1
|
7月前
|
C++
多重指针:深入解析、应用与示例
多重指针:深入解析、应用与示例
|
7月前
|
存储 C语言
C语言中的指针数组与多重指针
C语言中的指针数组与多重指针
52 0
|
7月前
|
存储 程序员 C++
指针数组和多重指针
指针数组和多重指针
66 2
|
Java .NET C#
《指针的编程艺术(第二版)》一导读
指针的编程艺术(第二版) C语言的特色就是“指针”(Pointer),这是个让人又爱又难受的主题。有一句话是这么说的,学过C,而不会指针,那只能说你看过C。熟悉指针的人,会将指针比喻成天上那一颗最美的星星,而让不懂指针的人,头上冒星星,同样是星星,但却是完全不同的境遇。
1631 0
|
存储 安全 Java
Go基础:指针地址、指针类型、多重指针、指针运算
Go基础:指针地址、指针类型、多重指针、指针运算
305 0
Go基础:指针地址、指针类型、多重指针、指针运算