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

发布于 2024-12-11 04:47:49 字数 578 浏览 0 评论 0原文

看一下这个代码片段:

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

那么,在这两种指针到指针的声明中,哪种方式(也许)更可取,这两种方式之间有什么技术差异吗?

Have a look at this code snippet:

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);

Output

$ ./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

So which way is (perhaps) more preferrable in those 2 declarations of pointer to pointer, and is there any technical difference between those two?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

_畞蕅 2024-12-18 04:47:49

从技术上讲,您只声明了一个指针到指针。

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< /代码>。

Technically, you've only declared one pointer-to-pointer.

int **ppi = π // first declaration

The second declaration is just a pointer which, when assigned, gets a copy of the first pointer pi's address.

Here's how you can prove it; after your test code, add this:

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);

The output will be:

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

When you change the value of pi (what it points to), dereferencing ppi will reflect the changes, as it points to pi, but because api was just made as a copy of pi before it changed, it will continue pointing to i.

執念 2024-12-18 04:47:49

第二个 (api) 没有声明指向指针的指针。它创建一个指向 int 的指针,并使用另一个指向 int 的指针的值对其进行初始化。

The second one (api) doesn't declare a pointer to pointer. It creates a pointer to int, and initializes it with the value of another pointer to int.

人心善变 2024-12-18 04:47:49

您的最后两个 printf(ppiapi)缺少第二个参数,因此它会打印该参数所在堆栈中的任何内容应该是(使用适当的警告进行编译会发现这一点)。 api 不是指向指针的指针,它是指向 int 的指针,与 pi 相同。声明指向指针的指针(忽略空格和括号样式)的唯一方法是 type **var

Your last two printfs (ppi and api) are missing their second argument, so it's printing whatever happens to be in the stack where said argument should be (compiling with appropriate warnings would have caught this). api is NOT a pointer to a pointer, it's a pointer to an int, same as pi. The ONLY way to declare a pointer to a pointer (ignoring spacing and parentheses styles) is type **var.

自演自醉 2024-12-18 04:47:49

类型定义了如何交互数据的语义,例如,您不应该将指向 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 限定的,就表明该值可以更改,并且它可能也可能不指向相同的分配内存。在我的示例中,我删除了旧指针,但这是您需要注意的特定功能。此外,如果调用者负责删除返回的任何新内存,也可能是特定于函数的,因此请阅读您看到的使用这些函数的任何函数的文档,并确保您记录了您写得好的任何函数。

The types defined the semantics of how you interact the data, you should not ever assign a pointer to int directly to a pointer to a pointer of an int, for example. However you might be wondering a use case of using a ** type.

For an example, look at this code I wrote:

#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;  
}

The output on my machine:

[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

There are functions and the standard library, and elsewhere, that take a pointer to a pointer of a type. As long as a parameter of ** is not const qualified, it indicates that the value can be changed and it may, or maynot point to the same allocated memory. In my example I deleted the old pointer, but that is function specific you need to watch out for. Also, if the caller is responsible to delete any new memory returned could also be function specific, so read the documentation of any functions you see that use these and make sure you document any that you write well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文