看一下这段代码:
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
那么在指向指针的那两个声明中,哪种方式(也许)更可取,这两者之间是否存在技术差异?
答案 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(ppi
和api
)错过了他们的第二个参数,因此它正在打印所有参数应该在堆栈中发生的事情(用适当的编译)警告会抓住这个)。 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限定的,它就表示该值可以更改,并且它可能或者可能不指向相同的已分配内存。在我的例子中,我删除了旧指针,但这是功能特定的,你需要注意。此外,如果调用者负责删除任何返回的新内存也可能是特定于功能的,那么请阅读您看到的使用这些内容的任何函数的文档,并确保记录您编写的任何内容。