这两种声明指针指针的方法有什么区别?

时间:2011-10-20 15:32:16

标签: c pointers

看一下这段代码:

int i = 10;
int *pi = &i;
int **ppi = π // first declaration
int *api = pi;   // second declaration

printf("i's value is: %d\n",i);
printf("pi's value is: %d\n",*pi);
printf("ppi's value is: %d, at the address: %d\n",**ppi);
printf("api's value is: %d, at the address: %d\n",*api);

输出

$ ./test
i's value is: 10
pi's value is: 10
ppi's value is: 10, at the address: 2686760
api's value is: 10, at the address: 2686760

那么在指向指针的那两个声明中,哪种方式(也许)更可取,这两者之间是否存在技术差异?

4 个答案:

答案 0 :(得分:4)

从技术上讲,你只声明了一个指向指针的指针。

int **ppi = π // first declaration

第二个声明只是一个指针,当被赋值时,它会获得第一个指针pi的地址的副本。

以下是你如何证明它;在测试代​​码之后,添加:

int i2 = 20;
pi = &i2;

printf("ppi's value is: %d, at the address: %d\n",**ppi,*ppi);
printf("api's value is: %d, at the address: %d\n",*api,api);

输出将是:

ppi's value is: 20, at the address: 2686764 (or some other address)
api's value is: 10, at the address: 2686760

当您更改pi(它指向的内容)的值时,取消引用ppi将反映更改,因为它指向pi,但因为api是只是在pi更改之前制作了i的副本,它将继续指向{{1}}。

答案 1 :(得分:0)

第二个(api)没有声明指向指针的指针。它创建一个指向int的指针,并使用指向int。

的另一个指针的值对其进行初始化

答案 2 :(得分:0)

你的最后两个printf s(ppiapi)错过了他们的第二个参数,因此它正在打印所有参数应该在堆栈中发生的事情(用适当的编译)警告会抓住这个)。 api不是指向指针的指针,它是指向int的指针,与pi相同。声明指针指针(忽略间距和括号样式)的唯一方法是type **var

答案 3 :(得分:0)

类型定义了如何交互数据的语义,例如,您不应该将指向int的指针直接分配给指向int的指针的指针。但是,您可能想知道使用**类型的用例。

举个例子,看看我写的这段代码:

#include <stdio.h>
#include <stdlib.h>

typedef struct fooStruct 
{
  int a;
  int b;
} FOO_STRUCT;

void multiReturns(int *a, FOO_STRUCT **b) {
  *a = 42;
  //b is a pointer that points to a FOO_STRUCT pointer
  if(*b) {
    free(*b);
    printf("Proof that we deleted memory.\n");
  }
  //This changes what b points to in main.
  *b = (FOO_STRUCT *)malloc(sizeof(FOO_STRUCT));
  printf("The new value of *b, this may or maynot be the same as before: %p\n", *b);
  //Parens for clarity, We dereferenced the pointer to the 
  //FOO_STRUCT pointer. Then, we derefrence the FOO_STRUCT
  //pointer to access its members.
  (*(*b)).a = 59;
  (*(*b)).b = 42;
  return;
}

int main(int argc, char **argv)
{
  int a = 0;
  FOO_STRUCT *b = (FOO_STRUCT *)malloc(sizeof(FOO_STRUCT));
  (*b).a = 1;
  (*b).b = 2;
  printf("BEFORE a = %d\n", a);
  printf("BEFORE b = %p\n", b);
  printf("BEFORE *b.a = %d\n", (*b).a);
  printf("BEFORE *b.b = %d\n", (*b).b);
  multiReturns(&a, &b);
  printf("AFTER a = %d\n", a);
  //The value AFTER b might have changed, depends on allocation factors..
  printf("AFTER b = %p\n", b);
  printf("AFTER *b.a = %d\n", (*b).a);
  printf("AFTER *b.b = %d\n", (*b).b);
  free(b);
  return 0;  
}

我机器上的输出:

[hart@katamari tests]$ gcc pointers.c -o ptr
[hart@katamari tests]$ ./ptr
BEFORE a = 0
BEFORE b = 0x19b41010
BEFORE *b.a = 1
BEFORE *b.b = 2
Proof that we deleted memory.
The new value of *b, this may or maynot be the same as before: 0x19b41010
AFTER a = 42
AFTER b = 0x19b41010
AFTER *b.a = 59
AFTER *b.b = 42

有一些函数和标准库,以及其他地方,它们指向一个类型的指针。只要**的参数不是const限定的,它就表示该值可以更改,并且它可能或者可能不指向相同的已分配内存。在我的例子中,我删除了旧指针,但这是功能特定的,你需要注意。此外,如果调用者负责删除任何返回的新内存也可能是特定于功能的,那么请阅读您看到的使用这些内容的任何函数的文档,并确保记录您编写的任何内容。