如何打印指针指针

时间:2016-11-29 13:08:41

标签: c pointers

我是一个新手试图理解双指针的工作和打印双指针。我将m递增1,但它始终指向p指向的最后一个值。有人可以帮助我吗?

#include <stdio.h>

int main () {
   /* an array with 5 elements */
   double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
   double *p;
   double **m;
   int i;

   p = balance;
   m = &p;
   /* output each array element's value */
   printf( "Array values using pointer\n");

   for ( i = 0; i < 5; i++ ) {
     printf("*(p + %d) : %f\n",  i, *(p+i) );
   }

   for ( i = 0; i < 5; i++ ) {
     printf("**(m + %d) : %f\n",  i, *m);
     m++;
   }

   printf( "Array values using balance as address\n");

   for ( i = 0; i < 5; i++ ) {
      printf("*(balance + %d) : %f\n",  i, *(balance + i) );
   }
   return 0;
}

2 个答案:

答案 0 :(得分:1)

您的数组balance就像这样

+--------+--------+--------+--------+--------+
| 1000.0 |    2.0 |    3.4 |   17.0 |   50.0 |
+--------+--------+--------+--------+--------+

初始化pm之后,就像这样:

+---+
| m |
+---+
|
v
+---+
| p |
+---+
|
V
+--------+--------+--------+--------+--------+
| 1000.0 |    2.0 |    3.4 |   17.0 |   50.0 |
+--------+--------+--------+--------+--------+

也就是说,m指向p的位置,p指向balance数组的第一个值。

当您取消引用m时(即当您执行*m时),您将获得m所指向的值。此值是另一个指针(p),您需要取消引用才能访问数组中的元素。

使用m balance中的第二个元素(即balance[1])为(*m)[1]

现在,如果您增加m(例如m++),它将指向p的下一个元素:

     +---+
     | m |
     +---+
     |
     v
+---+
| p |
+---+
|
V
+--------+--------+--------+--------+--------+
| 1000.0 |    2.0 |    3.4 |   17.0 |   50.0 |
+--------+--------+--------+--------+--------+

您可以在此处清楚地看到问题:它不再指向p,您再也无法使用它来访问balance数组。在增量之后取消引用m将导致未定义的行为

此外,对于任何指针或数组,数组索引表达式和指针算术表达式是相等的。因此,对于balance,表达式balance[i]等于*(balance + i)。它们之间确实没有区别。

答案 1 :(得分:0)

执行

之后
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
double **m;

p = balance;
m = &p;

以下都是真的:

  m == &p                     // double **
 *m ==  p == &balance[0]      // double *
**m == *p ==  balance[0]      // double

(*m)[i] == p[i] == balance[i] // double

请记住表达式a[i]定义为*(a + i);给定地址a,偏移i元素(不是字节 1 )并取消引用结果。

这意味着*p相当于*(p + 0),相当于p[0]。因此,您可以使用p[i]代替balance[i]。自*m == p起,您也可以使用(*m)[i]代替p[i]。括号是必要的 - 一元*的优先级低于后缀[],因此*m[i]将被解析为*(m[i]),这不是您想要的。

您可以直接将p增加到“走遍”balance数组:

p = balance; // p == &balance[0];
for ( i = 0; i < 5; i++ )
  printf( "%f\n", *p++ );

每次循环时,p都会递增以指向balance的下一个元素。

您可以使用表达式(*m)执行类似的操作:

p = balance; // p == &balance[0]
m = &p;      

for ( i = 0; i < 5; i++ )
  printf( "%f\n", (*m)++ );

同样,*m周围的括号是必要的;由于postfix ++的优先级高于一元*,因此表达式*m++将被解析为*(m++),这不是我们想要的。我们不想更改m的值,我们希望更改m 指向的值,在本例中为p

现在,假设我们完全离开了p;我们可以这样做:

double balance[5] = { ... };
double **m;

*m = balance;

没有。在此示例中,m无效指针;它尚未初始化为指向任何有意义的位置,因此*m将调用未定义的行为(可包括但不限于段错误)。 m 指向double *类型的对象,然后才能取消引用它。必须有像p这样的中间人才能使该计划奏效。

<小时/>

  1. 指针算法始终考虑指向类型的大小 - 如果a指向类型为T的对象,则a + 1将生成下一个对象的地址键入T,它可能比当前地址多1个字节。