博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《指针的编程艺术(第二版)》一3.6 多重指针
阅读量:7009 次
发布时间:2019-06-28

本文共 3310 字,大约阅读时间需要 11 分钟。

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

3.6 多重指针

指针的编程艺术(第二版)

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

范例starstarPointer-3

/* starstarPointer-3.c */#include 
#include
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需经过两次的间接访问才能得到值,用图表示如下。
从图中可以很容易地得到答案。比较复杂的是当*和++或--混合使用时就必须非常小心,分析++或--是作用于地址还是值。请参阅范例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;
}

输出结果
我们用图来辅助说明以上的变量定义。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数组的某一元素的地址,其示意图如下所示。
而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 
#include
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是一个数组指针,每一个元素都指向字符的指针,其示意图如下。
接下来的语句

  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个,这才符合访问值的条件。

转载地址:http://buitl.baihongyu.com/

你可能感兴趣的文章